1, Rights Management Overview
Permission management generally refers to that users can access and only access their authorized resources according to the security rules or security policies set by the system. Permission management appears in almost any system, as long as there are users and passwords. Many people often confuse the concepts of "user identity authentication", "password encryption" and "system management" with the concept of authority management.
Role Based Access Control (RBAC) is the most used function in permission management.
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-tyto89pm-1640700920586) (/ upload / 2021 / 12 / 1640696519 (1)] -3f53b312c7bd42449d0acb9315987af0 png)
When permission management needs to be used in the project, we can choose to implement it ourselves (RBAC system) or use the framework implemented by a third party.
Realize the necessary functions of permission management system:
- 1. Permission management (custom permission annotation, loading permission)
- 2. Role management (add, edit, delete, associate permissions)
- 3. User management (add, edit, delete, associate users)
- 4. Login function (define login interceptor and realize login logic and logout function)
- 5. Permission interception (define permission interceptor and implement interception logic)
What problems can the framework help us solve in the permission management system?
function | What the permission framework can do |
Authority management | × |
Role management | × |
user management | × |
Login function | √ (password encryption, verification code, remember me) |
Permission interception | √ (many built-in interceptors, labels / comments / programming methods for authority authentication) |
Other functions | √ (cache, session management, etc.) |
Here we introduce two common permission management frameworks:
1,Apache Shiro
Apache Shiro is a powerful and easy-to-use Java security framework. More and more people use Apache Shiro. It can realize the functions of authentication, authorization, password and session management.
2,Spring Security
Spring Security is also a popular security rights management framework, which is closely combined with spring.
3. Comparison between Shiro and Spring Security
Shiro is easier to use and understand than Spring Security,
Shiro can run independently without binding to any framework or container, and Spring Security must have a Spring environment,
Shiro may not be as powerful as Spring Security, but it may not need so complex things in actual work, so a small and simple Shiro is enough. There is no need to tangle about which of them is better. It would be better to solve the project problems more simply.
2, Shiro overview
1. What can Shiro do
Shiro can help us complete: authentication, authorization, encryption, session management, integration with the Web, caching, etc.
2. Shiro architecture
Shiro's main components include:
Subject,SecurityManager,Authenticator,Authorizer,SessionManager,CacheManager,Cryptography,Realms.
[the external chain picture transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG lkztwjsm-1640700920594) (/ upload / 2021 / 12 / 1640696637 (1)] - ecf4f09271544c0bb2ac00ac49427a6a png)
-
Subject (user): the user accessing the system. The subject can be a user, a program, etc., and the person authenticating is called the subject; the term subject is a professional term, which basically means "current operating user". You can use: Subject currentUser = SecurityUtils.getSubject() to obtain the subject subject object anywhere in the program, Similar to employee user = usercontext getUser().
-
SecurityManager (Security Manager): it is the core of Shiro function implementation. It is responsible for interacting with other components (authenticator, authorizer and cache controller) introduced later to realize various functions entrusted by Subject. It is somewhat similar to the DispatcherServlet front-end controller in Spring MVC, which is responsible for distribution scheduling.
-
Realms (data source): the Realm acts as a "bridge" or "connector" between Shiro and application security data. You can regard the Realm as a DataSource, that is, a secure data source. When performing authentication (login) and authorization (access control), Shiro will look up relevant comparison data from the Realm configured by the application to confirm whether the user is legal and the operation is reasonable.
3, Shiro certification and authorization
Shiro certification
The authentication process is the user's identity confirmation process. The realized function is the familiar login authentication. The user enters the account and password and submits it to the background. The background checks the correctness of the account and password by accessing the database.
There are generally two situations of login failure:
- Account error org apache. shiro. authc. UnknownAccountException
- Wrong password org apache. shiro. authc. IncorrectCredentialsException
Analysis of authentication process in Web Environment
Shiro can be used not only in the Web environment, but also in Java se.
Shiro authorization
- Authorization function in the system
This is the process of assigning related permissions to users. - Authentication function in the system
The process of judging whether the current user has access to a resource.
If the user's permissions cannot be managed in the system, there will be problems such as customer information disclosure and malicious data tampering. Therefore, in most applications, we will have permission management function.
Analysis of authorization process in Web Environment
4, How to configure Shiro in spring
1,stay web.xml Medium configuration Shiro of Filter 2,stay Spring Configuration in configuration file Shiro 3,Configure customization Realm: Implement custom authentication and authorization 4,to configure Shiro Cache policy used by entity classes 5,to configure SecurityManager 6,Configuration assurance Shiro inside Bean The declaration cycle is implemented Lifecycle Bean Post Processors 7,to configure AOP Method level permission check 8,to configure Shiro Filter
5, How to configure Shiro in springboot
1.0 import jar package to modify POM xml
<properties> <shiro.version>1.7.1</shiro.version> <thymeleaf.extras.shiro.version>2.0.0</thymeleaf.extras.shiro.version> </properties> <!--introduce shiro Permission framework integration--> <!--Shiro Core dependency --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>${shiro.version}</version> </dependency> <!-- Spring integrate Shiro rely on --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <!-- Shiro use EhCache Cache dependency --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>${shiro.version}</version> </dependency> <!-- Thymeleaf Template engine and Shiro Integrated dependency --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>${thymeleaf.extras.shiro.version}</version> </dependency>
2.0 Web environment configuration
package com.itzhouwei.web.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import com.itzhouwei.realm.EmployeeRealm; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { /***** * Inherit shiro and use its caching technology */ @Bean public EhCacheManager getEhCacheManager(){ EhCacheManager ehCacheManager=new EhCacheManager(); ehCacheManager.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml"); return ehCacheManager; } /*** * Using the shiro tag of the template file has an effect */ @Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); } /*** * md5 encryption and salt processing using shiro framework * */ @Bean public HashedCredentialsMatcher credentialsMatcher(){ HashedCredentialsMatcher hash=new HashedCredentialsMatcher("md5"); hash.setHashIterations(3); return hash; } /*** * Integrated shiro returns a custom data source for authentication login and authorized access control * @return */ @Bean public Realm employeeRealm(){ EmployeeRealm employeeRealm = new EmployeeRealm(); employeeRealm.setCredentialsMatcher(credentialsMatcher()); //Set cache manager for Realm employeeRealm.setCacheManager(getEhCacheManager()); return employeeRealm; } /**** * JSESSIONID will appear when solving integration shiro redirection, * An error of 400 will appear on the page * @return */ @Bean public DefaultWebSessionManager sessionManager(){ DefaultWebSessionManager sessionManager=new DefaultWebSessionManager(); sessionManager.setSessionIdUrlRewritingEnabled(false); return sessionManager; } /*** * Integrated shiro configures a security manager Bean * @return */ @Bean public DefaultWebSecurityManager securityManager(){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); securityManager.setRealm(employeeRealm()); securityManager.setSessionManager(sessionManager()); return securityManager; } /**** * The core security interface of Shiro is returned to configure which resources can be accessed without authorization * @return */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(){ ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager()); shiroFilterFactoryBean.setLoginUrl("/static/login.html"); Map<String,String>map=new LinkedHashMap<>(); //Exclude static resources that do not need to be intercepted and login and logout //anon requests for this path can be accessed without logging in map.put("/favicon.ico","anon"); map.put("/static/**","anon"); map.put("/login","anon"); //After logging out, the user information in shiro will be automatically cleaned up map.put("/logout","logout"); //All requests must be intercepted //Except for the resources excluded above, other resources can only be accessed after logging in map.put("/**","authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } /** * Open Shiro annotation Notifier */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){ AuthorizationAttributeSourceAdvisor auth=new AuthorizationAttributeSourceAdvisor(); auth.setSecurityManager(securityManager()); return auth; } /** * Set to use CGlib proxy instead * See DefaultAopProxyFactory#createAopProxy for details */ @Bean public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } }
3.0 custom realm
package com.itzhouwei.realm; import com.itzhouwei.domain.Employee; import com.itzhouwei.domain.Role; import com.itzhouwei.service.IEmployeeService; import com.itzhouwei.service.IPermissionService; import com.itzhouwei.service.IRoleService; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; 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.apache.shiro.util.ByteSource; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; import java.util.stream.Collectors; public class EmployeeRealm extends AuthorizingRealm { @Autowired private IEmployeeService service; @Autowired private IRoleService roleService; @Autowired private IPermissionService permissionService; /**** * Authorization (authority judgment) * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { Employee employee = (Employee) principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); //Super administrator if (employee.isAdmin()){ List<String> roles=roleService.selectAll().stream().map(Role::getSn).collect(Collectors.toList()); //The role does not support generic configuration, so you need to query it in the database yourself info.addRoles(roles); info.addStringPermission("*:*"); return info; } // Query the role code owned by the user according to the user's id List<String> roles= roleService.queryByEmployee(employee.getId()); info.addRoles(roles); // Query the permission expression owned by the user according to the user's id List<String> list = permissionService.queryByEmployeeId(employee.getId()); info.addStringPermissions(list); return info; } /***** * Perform authentication (login) operation * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { String username = (String) authenticationToken.getPrincipal(); Employee employee=service.queryByUserName(username); if (employee==null) { return null; } return new SimpleAuthenticationInfo(employee,employee.getPassword(), ByteSource.Util.bytes(employee.getSalt()), this.getName()); } }
4.0 modify the login method in the login control layer
package com.itzhouwei.web.controller; import com.itzhouwei.exception.BusinessException; import com.itzhouwei.exception.BusinessExceptionCode; import com.itzhouwei.qo.JsonResult; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class LoginController { @ResponseBody @RequestMapping("/login") public JsonResult login(String username, String password){ try{ UsernamePasswordToken token=new UsernamePasswordToken(username,password); Subject subject= SecurityUtils.getSubject(); System.out.println(subject); subject.login(token); subject.getSession().setAttribute("EMPLOYEE_IN_SESSION",subject.getPrincipal()); return new JsonResult(true,"Login succeeded"); }catch (UnknownAccountException ignored){ throw new BusinessException(BusinessExceptionCode.UNKNOWN_ACCOUNT_ERROR); }catch (IncorrectCredentialsException e){ throw new BusinessException(BusinessExceptionCode.LOGIN_USER_ERROR); }catch (Exception e){ e.printStackTrace(); return new JsonResult(false, "Login exception, please contact the administrator"); } } @RequestMapping("/logout") public String logout(){ return "redirect:/static/login"; } }
5.0 annotation is completed by placing the annotation provided by Shiro on the processing method of the controller.
// @RequiresRoles("hr") / / determine roles @RequiresPermissions("employee:saveOrUpdate") //Judgment authority @RequestMapping("/saveOrUpdate") @ResponseBody public JsonResult saveOrUpdate(Model model, Employee emp,Long [] roleIds){ try{ if (emp.getId()!=null){ service.update(emp,roleIds); }else{ service.insert(emp,roleIds); } }catch (Exception ex){ return new JsonResult(false,ex.getMessage()); } return new JsonResult(true,"success"); }
6.0 configure template page button control
6.1 Add the following constraint header to the page <html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> 6.2 Use labels on pages <a href="#" class="btn btn-success btn-input" style="margin: 10px" shiro:hasPermission="department:saveOrUpdate"> <span class="glyphicon glyphicon-plus"></span> add to </a>
7.0 integrate EhCache cache to avoid multiple queries to the database
7.1 create ehcache / ehcache Shiro. In the resource directory XML file
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="600" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
parameter | explain |
maxElementsInMemory | Maximum number of cache objects |
eternal | Whether the object is permanently valid. Once set, timeout will not work |
timeToIdleSeconds | The idle time of an object refers to how long the object will become invalid without being accessed (unit: seconds). It is only used when eternal = false. The object is not permanently valid. It is optional. The default value is 0, that is, the idle time is infinite. |
timeToLiveSeconds | Object survival time refers to the time (in seconds) required for an object from creation to expiration. It is only used when eternal = false, and the object is not permanently valid. The default is 0, that is, the object survival time is infinite. |
memoryStoreEvictionPolicy | When the maxElementsInMemory limit is reached, Ehcache will clean up the memory according to the specified policy. |
strategy | explain |
LRU | By default, the least recently used and the longest unused elements will be cleared out of the cache |
FIFO | First in, first out. If a data enters the cache first, it should be eliminated first |
LFU | Less use means that the elements that have been used least all the time have a hit attribute (hit rate). The elements with the lowest hit value will be cleared out of the cache |