catalogue
4.3 implementation of two methods
4.4.2 AuthorizationAttributeSourceAdvisor
1. Preface
In previous permission management, our permission management usually has the following steps:
1. Create users and assign permissions.
2. When the user logs in, the permission interceptor intercepts the request and identifies the current user's login information
3. Judge whether you have permission from the permission table
The following three questions can be extracted from the above steps.
1. How to make Shiro intercept requests.
In web development, Shiro will provide an interceptor to intercept requests.
2. How does Shiro determine the identity of the user who initiated the request?
In web development, it will be judged by session. If session is disabled, some methods may need to be rewritten.
3. How to judge permissions?
Shiro uses realm to determine permissions.
2. Shiro's introduction
- Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, password, and session management. With Shiro's easy to understand API, you can get any application quickly and easily, from the smallest mobile application to the largest network and enterprise application.
- Shiro can be used not only in the Java EE environment, but also in Java se
3. Shiro function
- Authentication: authentication, which verifies whether a user has an identity.
- Authorization: permission verification to verify whether an authenticated user has a certain permission. Determine who can access what.
- Session Management: Session Management, which manages the session after the user logs in,
- Cryptography: encryption, the use of cryptography to encrypt data, such as encrypted passwords.
- Web Support: Web Support, which can be easily integrated into the web environment.
- Caching: caching, which caches the user's data,
- Concurrency: concurrency. Apache Shiro supports multithreaded applications with concurrency, that is, concurrent verification in multithreaded applications.
- Testing: testing, which provides support for testing.
- Run as: allows users to log in as other users.
- Remember me
4. Basic use
4.1 introducing a dependency
Create a new Springboot based Web project and introduce Shiro dependency.
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency>
4.2 configuring two beans
Create a shiroconfig configuration class to configure the SecurityManager, the core security manager of Shiro. Three beans are configured here. The UserAuthorizingRealm in the formal parameter is scanned through @ Component. You can configure it directly in shiroconfig without adding this annotation.
/** * Configure the security manager, the core component of Shiro * * @param userRealm * @return */ @Bean public SecurityManager securityManager(UserAuthorizingRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); // Cancel the memberme parameter in the Cookie securityManager.setRememberMeManager(null); // Configure custom Session manager // securityManager.setSessionManager(mySessionManager()); return securityManager; }
Then configure Shiro's filter factory class, inject the security manager configured in the previous step, and configure the corresponding filter rules.
//*authc: the configured URLs must be authenticated before they can be accessed. It is a built-in filter in Shiro //*Corresponding implementation class @ see org.apache.shiro.web.filter.authc.FormAuthenticationFilter // //*anon: it is also built in Shiro. Its corresponding filter is empty and does nothing. It can be understood as not intercepting //*Corresponding implementation class @ see org.apache.shiro.web.filter.authc.AnonymousFilter @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // Login page, no right to time limited jump path shiroFilterFactoryBean.setLoginUrl("/login"); // Configure interception rules Map<String, String> filterMap = new LinkedHashMap<>(); // Home page configuration release filterMap.put("/", "anon"); // The login page and login request path need to be released filterMap.put("/login", "anon"); filterMap.put("/do_login", "anon"); // All other unconfigured paths need to be verified, otherwise jump to the login page filterMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; }
LinkedHashMap is used to maintain the order. The configuration order of Filter cannot be disordered. The Filter is matched according to the order we configure. A wide range of filters should be placed in the back, / * * if this one is placed in the front, it will match and will not go back.
4.3 implementation of two methods
In the security manager configuration in the previous step, we injected a UserAuthorizingRealm object through formal parameters. This is the process related to authentication and authorization, which needs to be implemented by ourselves. After inheriting the authorizing realm, we need to implement two abstract methods, one is authentication and the other is authorization. The two methods look very similar. Don't confuse them.
doGetAuthenticationInfo: authentication. This is equivalent to logging in. Only after logging in can the following authorized operations be carried out. Some operations that only need login permission can be accessed after successful login. For example, the authc filter configured in the previous step only needs login permission.
doGetAuthorizationInfo: authorization. After authentication, only login permission and more fine-grained permission control, such as menu permission, button permission, and even method call permission, can be easily realized through authorization. In this method, we can get the currently logged in user, and then give the user some or all permissions according to the actual business. Of course, we can also give the user some roles, and then we can authenticate according to the roles. The following demonstration code only adds permissions. Given roles, you can call addRoles() or setRoles() methods to pass in the role collection.
package com.example.shirodemo.shiro; import com.example.shirodemo.entity.User; import com.example.shirodemo.service.LoginService; import org.apache.shiro.SecurityUtils; 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.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.*; /** * UserRealm,Achieve authentication and authorization * * @author woqing */ @Component public class UserAuthorizingRealm extends AuthorizingRealm { @Autowired private LoginService loginService; /** * Authorization verification to obtain authorization information */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { User user = (User) principalCollection.getPrimaryPrincipal(); List<String> perms; // The system administrator has the highest authority if (User.SUPER_ADMIN == user.getId()) { perms = loginService.getAllPerms(); } else { perms = loginService.getUserPerms(user.getId()); } // Permission Set collection Set<String> permsSet = new HashSet<>(); for (String perm : perms) { permsSet.addAll(Arrays.asList(perm.trim().split(","))); } // Return permission SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setStringPermissions(permsSet); return info; } /** * Login authentication to obtain identity information */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // Get user User user = loginService.getUserByUsername(token.getUsername()); if (user == null) { throw new UnknownAccountException("Incorrect account or password"); } // Determine whether the user is locked if (user.getStatus() == null || user.getStatus() == 1) { throw new LockedAccountException("Account locked,Please contact the administrator"); } // Verify password if (!user.getPassword().equals(new String(token.getPassword()))) { throw new UnknownAccountException("Incorrect account or password"); } user.setSessionId(SecurityUtils.getSubject().getSession().getId().toString()); // Set last logon time user.setLastLoginTime(new Date()); // The login information of users can be persisted here. This is just a demonstration and there is no connection to the database return new SimpleAuthenticationInfo(user, user.getPassword(), getName()); } }
After this configuration is completed, you can perform complex permission control based on the URL. We can configure different permissions for the URL through different filters.
Shiro provides many built-in filters, the first and second are the most commonly used. If we are not satisfied with the effect, we can also customize the filter to realize permission control.
4.4 authority control
4.4.1 AdvisorAutoProxyCreator
For annotated permission control, two beans need to be configured. The first is advisor autoproxycreator and proxy generator. Spring AOP needs to be used to scan @ RequiresRoles and @ RequiresPermissions and other annotations, generate proxy classes and enhance functions, so as to realize permission control. It needs to be used together with the AuthorizationAttributeSourceAdvisor, otherwise the permission annotation is invalid.
/** * The proxy generator needs spring AOP to scan annotations such as @ RequiresRoles and @ RequiresPermissions. * Generate proxy classes to enhance functions, so as to realize permission control. * It needs to be used together with the AuthorizationAttributeSourceAdvisor, otherwise the permission annotation is invalid. */ @Bean public DefaultAdvisorAutoProxyCreator lifecycleBeanPostProcessor() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); // It needs to be set to True here, otherwise the @ RequiresPermissions annotation verification will not take effect advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; }
4.4.2 AuthorizationAttributeSourceAdvisor
The defaultadvisor autoproxycreator configured above is equivalent to a facet, and the following class is equivalent to a pointcut. The two can realize annotation permission control together.
/** * The defaultadvisor autoproxycreator configured above is equivalent to a facet, and the following class is equivalent to a pointcut. The two can realize annotation permission control together. */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; }
After configuring the above two beans, we can use annotations to control permissions. There are many permission annotations in Shiro. In fact, we most commonly use @ RequiresRoles AND @ RequiresPermissions. The former is role verification AND the latter is permission verification. Both of them can pass in two parameters. Value is required. You can pass in a character array to represent one OR more roles (permissions). The other parameter logical has two optional values, AND and OR. The default value is AND, indicating whether this group of roles (permissions) must have OR only need one to access.
4.5 take chestnuts for example:
The above code indicates that the info() method needs the user:list or user:list permission of the current login user to access.
More shiro annotation parsing: Instructions for shiro's @ RequiresPermissions annotation