Apache Shiro是一个强大的,易用的Java安全框架。它被用作于认证,授权,加密,session管理。依赖于Shiro简单易懂的API,就可以快速的构建包括手机,大型web和商业应用。
下面介绍简单的shiro配置:
首先在工程Maven依赖里面引入shiro:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency>
其次在Web.xml里面配置shiro拦截器:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency>
然后在web.xml添加shiro配置文件路径读取:
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:/spring/appCtx-dubbo.xml classpath:/spring/appCtx-aop.xml classpath:/spring/appCtx-base.xml classpath:/spring/appCtx-cache.xml classpath:/spring/appCtx-shiro.xml </param-value> </context-param>
然后就可以编辑自己Reaml类进行权限控制,示例如下:
package com.onlyou.olyfinance.common.shiro; import java.util.*; import com.onlyou.olyfinance.common.constant.CodeInfoConstants; import com.onlyou.olyfinance.common.util.BeanUtils; import com.onlyou.olyfinance.common.util.CarrierUtil; import com.onlyou.olyfinance.sys.entity.CarrierEntity; import com.onlyou.olyfinance.sys.service.IUsrAuthService; import com.onlyou.olyfinance.sys.service.IUsrRoleRelService; import com.onlyou.olyfinance.sys.vo.MenuVO; import com.onlyou.olyfinance.sys.vo.TreeMenuVO; import com.onlyou.olyfinance.sys.vo.UsrManageVO; import com.onlyou.olyfinance.sys.vo.UsrRoleRelManageVO; import com.onlyou.olyfinance.usr.vo.LoginUserVO; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.onlyou.framework.exception.BusinessException; /** * shiro权限控制 * */ public class MngRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private IUsrAuthService usrAuthService; @Autowired private IUsrRoleRelService usrRoleRelService; /** * 认证 获取认证信息 */ protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authToken; logger.debug("用户登录:" + token.getUsername()); try { UsrManageVO user = usrAuthService.findUserByName(token .getUsername(),CarrierUtil.getCarrierId()); if (null == user) { throw new BusinessException("用户名或密码不正确"); } LoginUserVO loginUser = new LoginUserVO(); loginUser.setId(user.getId()); loginUser.setCarrierId(user.getCarrierId()); loginUser.setUsrAccount(user.getUsrAccount()); loginUser.setHeadPicUri(user.getAvatarFileId()); loginUser.setTicket(UUID.randomUUID().toString()); loginUser.setAdminFlag(CodeInfoConstants.YES_STATUS_VALUE .equals(user.getIsSysAdmin())); loginUser.setUserName(user.getStaffNm()); AuthenticationInfo authcInfo = new SimpleAuthenticationInfo( loginUser, user.getUsrPwd(), getName()); return authcInfo; } catch (BusinessException e) { logger.error(e.getMessage(), e); throw new AuthenticationException(e.getMessage(), e); } catch (Throwable t) { logger.error(t.getMessage(), t); throw new AuthenticationException("未知错误,请查看日志", t); } } /** * 校验密码处理 */ @Override protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException { try { super.assertCredentialsMatch(token, info); } catch (ExcessiveAttemptsException e) { throw e; } catch (IncorrectCredentialsException e) { logger.error(e.getMessage(), e); throw new AuthenticationException("用户名或密码不正确", e); } catch (Throwable t) { logger.error(t.getMessage(), t); throw new AuthenticationException("未知错误,请查看日志", t); } // 校验通过进行初始化角色,菜单,授权等信息 this.initLoginUserVO((LoginUserVO) info.getPrincipals() .getPrimaryPrincipal()); } /** * 授权 鉴权回调函数,提取当事人的角色和权限 角色、菜单/按钮权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo(); LoginUserVO loginUser = (LoginUserVO) principals.getPrimaryPrincipal(); if (loginUser != null) { // 权限初始化 Map<String, UsrRoleRelManageVO> roleMap = loginUser .getRoleMap(); if (roleMap != null) { for (UsrRoleRelManageVO role : roleMap.values()) { authInfo.addRole(role.getRoleEncrypt()); } logger.info("roles: " + authInfo.getRoles()); } // permissions List<MenuVO> menuList = loginUser.getMenuList(); if (menuList != null) { for (MenuVO menu : menuList) { String menuUri = menu.getMenuUri(); if (StringUtils.isNotBlank(menuUri)) { authInfo.addStringPermission(menuUri); } } logger.info("menu permissions: " + authInfo.getStringPermissions()); } } return authInfo; } /** * 清空权限(运营商角色判断是否重置) * * @param principals * @param initFlag */ public void cleanCache(PrincipalCollection principals, boolean initFlag) { LoginUserVO loginUser = (LoginUserVO) principals.getPrimaryPrincipal(); if (loginUser != null) { if (initFlag) { this.initLoginUserVO(loginUser); } super.clearCachedAuthorizationInfo(principals); } } /** * 加载角色,菜单,权限的信息 * * @param loginUser */ private void initLoginUserVO(LoginUserVO loginUser) { UsrRoleRelManageVO roleCondition = new UsrRoleRelManageVO(); roleCondition.setUsrId(loginUser.getId()); roleCondition.setIsValid(CodeInfoConstants.YES_STATUS_VALUE); List<UsrRoleRelManageVO> roleList = usrRoleRelService .list(roleCondition); Map<String, UsrRoleRelManageVO> roleMapAll = new HashMap<>(); for (UsrRoleRelManageVO roleVO : roleList) { String roleId = roleVO.getRoleId(); if(CodeInfoConstants.YES_STATUS_VALUE.equals(roleVO.getIsDefaultRole())){ loginUser.setRoleId(roleId); } roleMapAll.put(roleId, roleVO); } loginUser.setRoleMap(roleMapAll); // 缓存上菜单列表供页面使用 Set<MenuVO> menuSet =new HashSet<>(); for (UsrRoleRelManageVO roleVO : roleMapAll.values()) { List<MenuVO> menuList = usrAuthService .getMenusByRolePermission(roleVO.getRoleId()); menuSet.addAll(menuList); } List<MenuVO> menuList =new ArrayList<>(menuSet); //因为HashSet是无续的,这里重新排序 Collections.sort(menuList, new Comparator<MenuVO>() { @Override public int compare(MenuVO o1, MenuVO o2) { return o1.getOrderNo().compareTo(o2.getOrderNo()); } }); loginUser.setMenuList(menuList); loginUser.setCarrier(this.usrRoleRelService.selectByPrimaryKey(CarrierEntity.class,loginUser.getCarrier())); List<TreeMenuVO> treeMenuVOList =initTreeMenuVO(menuList); loginUser.setTreeMenuList(treeMenuVOList); } private List<TreeMenuVO> initTreeMenuVO(List<MenuVO> menuList){ List<TreeMenuVO> list =new ArrayList<>(); for(MenuVO menuVO:menuList){ if("-1".equals(menuVO.getSupMenuId())){ TreeMenuVO child =new TreeMenuVO(menuVO); list.add(child); findChild(child,menuList); } } return list; } private void findChild(TreeMenuVO parent,List<MenuVO> menuList){ for(MenuVO menuVO:menuList){ if(parent.getMenuId().equals(menuVO.getSupMenuId())){ TreeMenuVO child =new TreeMenuVO(menuVO); parent.addChild(child); findChild(child,menuList); } } } }
最后,在appctx-shiro.xml里面进行shiro的相关配置:
扫描二维码关注公众号,回复:
240226 查看本文章
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd" default-lazy-init="true"> <description>Shiro安全配置</description> <!-- Shiro's main business-tier object for web-enabled applications --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="shiroDbRealm" /> <property name="cacheManager" ref="shiroMemCachedManager" /> </bean> <!-- 項目自定义的Realm, 所有staffAccountService依赖的dao都需要用depends-on声明 --> <bean id="shiroDbRealm" class="com.onlyou.olyfinance.common.shiro.MngRealm"> <property name="credentialsMatcher"> <bean class="com.onlyou.olyfinance.common.shiro.RetryLimitCredentialsMatcher"> <property name="hashAlgorithmName" value="MD5" /> <property name="group" value="mclient1" /> <property name="cacheClient" ref="cacheClient" /> </bean> </property> </bean> <!-- Shiro Filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager" /> <property name="loginUrl" value="/login.enter.htm" /> <property name="unauthorizedUrl" value="/unauthorized.htm" /> <property name="successUrl" value="/usr/usrInfo.htm" /> <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource" /> <property name="filters"> <map> <entry key="authc"> <bean id="loginFormAuthenticationFilter" class="com.onlyou.olyfinance.common.shiro.LoginFormAuthenticationFilter"> <property name="usernameParam" value="username" /> <property name="passwordParam" value="password" /> <property name="failureKeyAttribute" value="shiroLoginFailure"/> </bean> </entry> <entry key="jCaptchaValidate"> <bean class="com.onlyou.olyfinance.common.jcaptcha.JCaptchaValidateFilter"> <property name="jcaptchaEbabled" value="true" /> <property name="jcaptchaParam" value="vcode" /> <property name="failureKeyAttribute" value="shiroLoginFailure" /> <property name="failureMsg" value="验证码不正确" /> <property name="errorLimitAttribute" value="errorTimes" /> <property name="errorLimit" value="3" /> </bean> </entry> <entry key="perms"> <!-- 自定义鉴权拦截器 --> <bean id="urlPermissionsFilter" class="com.onlyou.olyfinance.common.shiro.URLPermissionsFilter" /> </entry> </map> </property> </bean> <bean id="chainDefinitionSectionMetaSource" class="com.onlyou.olyfinance.common.shiro.MngMetaSource"> <!-- 默认的连接配置 --> <property name="filterChainDefinitions"> <value> #查看应用信息(代码版本,启动时间) /getAppInfo.json = anon #登出 /logout = logout #不验证资源 /favicon.ico = anon /assets/** = anon /unauthorized.htm = anon /jcaptcha.jpg* = anon #访问这些路径必须拥有某种权限 /login.enter.htm = jCaptchaValidate,authc #其它资源都要求用户 /** = user,perms </value> </property> </bean> <!-- 用户授权信息Cache, 采用MemCached --> <bean id="shiroMemCachedManager" class="com.onlyou.framework.cache.shiro.MemcachedManagerForShiro"> <property name="group" value="mclient1" /> <property name="cacheClient" ref="cacheClient" /> </bean> <!-- 保证实现了Shiro内部lifecycle函数的bean执行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
一些shiro的标签应用:
<shiro:authenticated> 登录之后 <shiro:notAuthenticated> 不在登录状态时 <shiro:guest> 用户在没有RememberMe时 <shiro:user> 用户在RememberMe时 <shiro:hasAnyRoles name="abc,123" > 在有abc或者123角色时 <shiro:hasRole name="abc"> 拥有角色abc <shiro:lacksRole name="abc"> 没有角色abc <shiro:hasPermission name="abc"> 拥有权限abc <shiro:lacksPermission name="abc"> 没有权限abc <shiro:principal> 显示用户登录名
本章只是在应用层面上对shiro配置进行阐述,了解原理可参考以下链接:
http://blog.csdn.net/xiaoyao8903/article/details/53244835
http://jinnianshilongnian.iteye.com/blog/2018936