Apache Shiro is a powerful, easy-to-use Java security framework. It is used for authentication, authorization, encryption, session management. Relying on Shiro's easy-to-understand API, you can quickly build mobile, large-scale web and commercial applications.
The following describes a simple shiro configuration:
First, introduce shiro in the project Maven dependency:
<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>
Next, configure the shiro interceptor in Web.xml:
<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>
Then add the shiro configuration file path to web.xml to read:
<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>
Then you can edit your own Reml class for permission control, the example is as follows:
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 permission control * */ public class MngRealm extends AuthorizingRealm { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private IUsrAuthService usrAuthService; @Autowired private IUsrRoleRelService usrRoleRelService; /** * Certification to obtain certification information */ protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authToken; logger.debug("User login: " + token.getUsername()); try { UsrManageVO user = usrAuthService.findUserByName(token .getUsername(),CarrierUtil.getCarrierId()); if (null == user) { throw new BusinessException("The username or password is incorrect"); } 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("Unknown error, please check log", t); } } /** * Verify password processing */ @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("The username or password is incorrect", e); } catch (Throwable t) { logger.error(t.getMessage(), t); throw new AuthenticationException("Unknown error, please check log", t); } // Verify through initialization role, menu, authorization and other information this.initLoginUserVO((LoginUserVO) info.getPrincipals() .getPrimaryPrincipal()); } /** * Authorization authentication callback function to extract the roles and permissions of the parties, menu/button permissions */ @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo(); LoginUserVO loginUser = (LoginUserVO) principals.getPrimaryPrincipal (); if (loginUser != null) { // permission initialization 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; } /** * Clear permissions (operator role to determine whether to reset) * * @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); } } /** * Load role, menu, permission information * * @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); // Cache the menu list on the page for the page to use 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); //Because HashSet is non-continuous, reorder here 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); } } } }
Finally, configure shiro in appctx-shiro.xml:
<?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 Security Configuration</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> <!-- Project-customized Realm, all dao that staffAccountService depends on need to be declared with 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="The verification code is incorrect" /> <property name="errorLimitAttribute" value="errorTimes" /> <property name="errorLimit" value="3" /> </bean> </entry> <entry key="perms"> <!-- Custom Authentication Interceptor--> <bean id="urlPermissionsFilter" class="com.onlyou.olyfinance.common.shiro.URLPermissionsFilter" /> </entry> </map> </property> </bean> <bean id="chainDefinitionSectionMetaSource" class="com.onlyou.olyfinance.common.shiro.MngMetaSource"> <!-- Default connection configuration --> <property name="filterChainDefinitions"> <value> #View application information (code version, startup time) /getAppInfo.json = anon #Sign out /logout = logout #Do not validate resources /favicon.ico = anon /assets/** = anon /unauthorized.htm = anon /jcaptcha.jpg* = anon #Access these paths must have some kind of permission /login.enter.htm = jCaptchaValidate,authc #Other resources require the user /** = user,perms </value> </property> </bean> <!-- User authorization information Cache, using MemCached --> <bean id="shiroMemCachedManager" class="com.onlyou.framework.cache.shiro.MemcachedManagerForShiro"> <property name="group" value="mclient1" /> <property name="cacheClient" ref="cacheClient" /> </bean> <!-- Guaranteed to implement the bean execution of Shiro's internal lifecycle function --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> </beans>
Some shiro tag applications:
<shiro:authenticated> after login <shiro:notAuthenticated> when not logged in <shiro:guest> user without RememberMe <shiro:user> when the user is in RememberMe <shiro:hasAnyRoles name="abc,123" > when there are abc or 123 roles <shiro:hasRole name="abc"> has role abc <shiro:lacksRole name="abc"> No role abc <shiro:hasPermission name="abc"> has permission abc <shiro:lacksPermission name="abc"> No permission abc <shiro:principal> display user login name
This chapter only describes the shiro configuration at the application level. To understand the principle, please refer to the following links:
http://blog.csdn.net/xiaoyao8903/article/details/53244835
http://jinnianshilongnian.iteye.com/blog/2018936