What is Shiro
Official website: http://shiro.apache.org/
It is a mainstream Java security framework that does not rely on any container and can run in Java SE and Java EE Projects. Its main function is to authenticate, authorize, session management, encryption and other operations for users accessing the system.
Shiro is a systematic framework for security management.
Shiro core components
1. UsernamePasswordToken is used by Shiro to encapsulate the user's login information and create a Token using the user's login information.
2. SecurityManager, the core part of Shiro, is responsible for security authentication and authorization.
3. Suject, an abstract concept of Shiro, contains user information.
4. Realm is a module customized by developers. According to the needs of the project, the verification and authorization logic is written in realm.
5. AuthenticationInfo, the user's role information collection, which is used for authentication.
6. Authorioninfo, the permission information collection of the role, which is used during authorization.
7. DefaultWebSecurityManager, security manager, and developer defined realms need to be injected into DefaultWebSecurityManager for management before they can take effect.
8. ShiroFilterFactoryBean is a Filter factory. Shiro's basic operation mechanism is that developers customize rules and Shiro executes them. The specific execution operations are completed by Filter objects created by ShiroFilterFactoryBean.
Shiro's operation mechanism is shown in the figure below.
Relationship between user roles and permissions:
Each user will have corresponding roles, and each role has corresponding permissions; Generally, users will not be directly associated with permissions, but have corresponding permissions through associated roles.
Spring Boot integrates Shiro
1. Create Spring Boot application, integrate Shiro and related components, POM xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1.tmp</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
2. Custom Shiro filter
public class AccountRealm extends AuthorizingRealm { @Autowired private AccountService accountService; /** * to grant authorization * @param principalCollection * @return * AuthorzationInfo,The permission information collection of the role, which is used during authorization. */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //Get current user information Subject subject = SecurityUtils.getSubject(); Account account = (Account) subject.getPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //Set role info.addRole(account.getRole()); //Set permissions info.addStringPermission(account.getPerms()); return info; } /** * authentication * @param authenticationToken * @return * @throws AuthenticationException * AuthenticationInfo,The user's role information collection, which is used for authentication. */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; Account account = accountService.findUserByName(token.getUsername()); //Data can be found according to the user name if(account != null) { return new SimpleAuthenticationInfo(account,account.getPassword(),getName()); } return null; } }
3. Configuration class
@Configuration public class ShiroConfig { /** * ShiroFilterFactoryBean: *In the filter factory, Shiro's basic operating mechanism is that developers customize rules and Shiro executes them, * The specific execution operations are completed by Filter objects created by ShiroFilterFactoryBean. * @param securityManager * @return */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager); //Permission setting Map<String, String> map = new HashMap<>(); map.put("/main","authc"); map.put("/manage","perms[manage]"); map.put("/administrator","roles[administrator]"); factoryBean.setFilterChainDefinitionMap(map); //Set login page factoryBean.setLoginUrl("/login"); //Set unauthorized page factoryBean.setUnauthorizedUrl("/unauthorize"); return factoryBean; } /** *DefaultWebSecurityManager: * Security manager, the developer defined Realm needs to be injected into the DefaultWebSecurityManager for management before it can take effect. * @param accountRealm * @return */ @Bean public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(accountRealm); return securityManager; } /** * Realm:For the module customized by the developer, the verification and authorization logic is written in real according to the needs of the project. * @return */ @Bean public AccountRealm accountRealm() { return new AccountRealm(); } /** * Integration with thymeleaf * @return */ @Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); } }
4.Controller
@Controller public class AccountController { @GetMapping("/{url}") public String redirect(@PathVariable("url") String url) { return url; } @PostMapping("/login") public String adminLogin( String username, String password, Model model) { //Create subject object Subject subject = SecurityUtils.getSubject(); //Generate a token based on the user name and password UsernamePasswordToken token = new UsernamePasswordToken(username,password); try { subject.login(token); //After successful authentication, put the user information into the session Account account = (Account) subject.getPrincipal(); subject.getSession().setAttribute("userInfo",account); return "index"; } catch (Exception e) { e.printStackTrace(); model.addAttribute("msg","Wrong user name or password!Please log in again"); return "login"; } } @GetMapping("/unauthorize") @ResponseBody public String unAuthorize() { return "The page cannot be accessed without authorization"; } @GetMapping("/logout") public String LoginOut() { Subject subject = SecurityUtils.getSubject(); //subject will sign us out subject.logout(); return "login"; } }
Write authentication and authorization rules:
Authentication filter
anon: no certification required.
authc: must be certified.
authcBasic: http basic authentication is required.
user: you don't have to pass the certification, as long as you have been recorded by Shiro, for example: remember me.
Authorization filter
perms: you must have a permission to access.
Role: you must have a role to access.
Port: the requested port must be the specified value.
rest: the request must be based on RESTful, POST, PUT, GET and DELETE.
ssl: must be a secure URL request protocol, HTTPS.
Create 3 pages, main html,manage.html,administrator.html
Access rights are as follows:
1. You must log in to access main html
2. The current user must have manage authorization to access manage html
3. The current user must have the administrator role to access administrator html
Shiro integrates Thymeleaf
1,pom.xml import dependency
<dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
2. Add ShiroDialect to the configuration class
@Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); }
3,index.html
<!DOCTYPE html> <html lang="en" xmlns:th= "http://www.thymeleaf.org" xmlns:shiro= "http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="shortcut icon" href="#" /> </head> <body> <p>index</p> <div th:if="${session.userInfo} != null"> <span th:text="${session.userInfo.username} + 'welcome back'"></span> <a href="/logout">cancellation</a> </div> <a href="/main">main</a>| <div shiro:hasPermission="manage"> <a href="/manage">manage</a></br> </div> <div shiro:hasRole="administrator"> <a href="/administrator">administrator</a></br> </div> </body> </html>
**Take notes in your study and watch carefully