Introduction to Shiro
Apache Shiro is an open source lightweight Java security framework, which provides authentication, authorization, password management, session management and other functions. Compared with Spring Security, Shiro framework is more intuitive and easy to use, and can also provide robust security. In the traditional SSM framework, there are many steps to manually integrate Shiro configuration. For Spring Boot, Shiro officially provides Shiro Spring Boot web starter to simplify Shiro configuration in Spring Boot. Here are the steps to use Shiro Spring Boot web starter.
Integrate Shiro
1. Create project
First, create a normal Spring Boot Web project
Add Shiro dependency and page template dependency. The code is as follows:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thyrneleaf</artifactId> </dependency> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>
Note that there is no need to add spring boot starter web dependency here. Shiro spring boot web starter already relies on spring boot starter web.
At the same time, the Thymeleaf template is used in this case, so the Thymeleaf dependency is added. In addition, in order to use the shiro tag in Thymeleaf, the Thymeleaf extras shiro dependency is introduced.
2. Shiro basic configuration
2.1 application.properties
First, in application The basic information for configuring Shiro in properties is as follows:
shiro.enabled=true shiro.web.enabled=true shiro.loginUrl=/login shiro.successUrl=/index shiro.unauthorizedUrl=/unauthorized shiro.sessionManager.sessionidUrlRewritngEnabled=true shiro.sessionManager.sessionidCookieEnabled=true
Code interpretation:
• the configuration in line 1 indicates that Shiro configuration is enabled, and the default value is true
• the configuration in line 2 indicates that Shiro Web configuration is enabled, and the default value is true
• the configuration in line 3 indicates the login address, which is "login.jsp" by default
• the configuration in line 4 indicates the login success address, which is "/" by default.
• line 5 configuration indicates unauthorized default jump address.
• the configuration in line 6 indicates whether session tracking is allowed through URL parameters. If the website supports cookies, this option can be turned off and the default is true
• the configuration in line 7 indicates whether session tracking is allowed through cookies. The default value is true
2.2 ShiroConfig.class
After configuring the basic information, configure Shiro in the Java code and provide two basic beans. The code is as follows:
ShiroConfig.class
package org.sang.shiro; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.realm.Realm; import org.apache.shiro.realm.text.TextConfigurationRealm; import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition; import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ShiroConfig { @Bean public Realm realm() { TextConfigurationRealm realm = new TextConfigurationRealm(); realm.setUserDefinitions("sang=123,user\n admin=123,admin"); realm.setRoleDefinitions("admin=read,write\n user=read"); return realm; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); chainDefinition.addPathDefinition("/login", "anon"); chainDefinition.addPathDefinition("/doLogin", "anon"); chainDefinition.addPathDefinition("/logout", "logout"); chainDefinition.addPathDefinition("/**", "authc"); return chainDefinition; } @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } }
Code interpretation:
Two key beans are provided here, one is Realm and the other is ShiroFilterChainDefinition As for ShiroDialect, it is to support the use of Shiro tag in Thymeleaf. If Shiro tag is not used in Thymeleaf, ShiroDialect may not be provided.
Realm s can be customized realms or realms provided by Shiro. For simplicity, there is no database connection configured in this case. Here, two users are directly configured: sang/123 and admin/123, corresponding to the roles user and admin respectively. User has read permission and admin has read write permission.
The ShiroFilterChainDefinition Bean is equipped with basic filtering rules, "/ login" and "/ doLogin" can be accessed anonymously, "logout" is a logout login request, and other requests can be accessed only after authentication.
2.3 UserController.class
Next, configure the login interface and page access interface. The code is as follows:
UserController.class
package org.sang.shiro; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @Controller public class UserController { @PostMapping("/doLogin") public String doLogin(String username, String password, Model model) { UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); } catch (AuthenticationException e) { model.addAttribute("error", "User name or password input error!"); return "login"; } return "redirect:/index"; } @RequiresRoles("admin") @GetMapping("/admin") public String admin() { return "admin"; } @RequiresRoles(value = {"admin","user"},logical = Logical.OR) @GetMapping("/user") public String user() { return "user"; } }
Code interpretation:
In the doLogin method, first construct a UsernamePasswordToken instance, then obtain a Subject object and call the login method in the object to perform the login operation. During the execution of the login operation, when an exception is thrown, it indicates that the login fails, and returns to the login view with an error message; When login is successful, redirect to "/ index".
Next, expose two interfaces "/ Admin" and "/ user". For the "/ Admin" interface, you need to have the admin role to access it; For the "/ user" interface, you can access it with either admin role or user role.
2.4 WebMvcConfig.class
For other interfaces that can be accessed without roles, you can directly configure them in WebMvc. The code is as follows:
WebMvcConfig.class
package org.sang.shiro; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebMvcConfig implements WebMvcConfigurer{ @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); registry.addViewController("/index").setViewName("index"); registry.addViewController("/unauthorized").setViewName("unauthorized"); } }
2.5 ExceptionController.class
Next, create a global exception handler to handle global exceptions. This case mainly deals with authorization exceptions. The code is as follows:
package org.sang.shiro; import org.apache.shiro.authz.AuthorizationException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView; @ControllerAdvice public class ExceptionController { @ExceptionHandler(AuthorizationException.class) public ModelAndView error(AuthorizationException e) { ModelAndView mv = new ModelAndView("unauthorized"); mv.addObject("error", e.getMessage()); return mv; } }
When the user accesses an unauthorized resource, it jumps to the unauthorized view and carries an error message.
2.6 creating HTML pages
After the configuration is completed, five HTML pages are created in the resources/templates directory for testing.
(1) index.html, the code is as follows:
<!DOCTYPE html> <html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>Hello, <shiro:principal/></h3> <h3><a href="/logout">Logout login</a></h3> <h3><a shiro:hasRole="admin" href="/admin">Administrator page</a></h3> <h3><a shiro:hasAnyRoles="admin,user" href="/user">Ordinary user page</a></h3> </body> </html>
index.html is the home page after successful login. First, the user name of the current login user is displayed, and then a "log off login" link is displayed. If the current login user has the role of "admin", a hyperlink of "administrator page" is displayed;
If the user has the role of "admin" or "user", a hyperlink of "normal user page" will be displayed.
Note that the namespace imported here is xmlns:shiro=http://www.pollix.at/thymeleaf/shiro , which is inconsistent with the Shiro namespace imported in JSP.
(2) login.html, the code is as follows:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <form action="/doLogin" method="post"> <input type="text" name="username"><br> <input type="password" name="password"><br> <div th:text="${error}"></div> <input type="submit" value="Sign in"> </form> </div> </body> </html>
login.html is a common login page, which displays the login failure information through a div when the login fails.
(3) user.html, the code is as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Ordinary user page</h1> </body> </html>
user.html is an ordinary user information display page.
(4) admin.html, the code is as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Administrator page</h1> </body> </html>
admin.html is an ordinary administrator information display page.
(5) unauthorized.html, the code is as follows:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <h3>Unauthorized, illegal access</h3> <h3 th:text="${error}"></h3> </div> </body> </html>
unauithorized.html is a display page of authorization failure, which also displays the information of authorization error.