Springboot elegantly integrates Shiro for login verification and authority authentication (with source code download)
Springboo configures Shiro for login Verification, authority authentication, demo demonstration attached.
We are committed to allowing developers to quickly build a basic environment and get applications running. We provide usage examples for users to refer to and allow beginners to get started quickly.
The source code address of this blog project:
Project source code github address
Project source code domestic gitee address
Dependencies
<!-- Shiro核心框架 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.9.0</version> </dependency> <!-- Shiro使用Spring框架 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.9.0</version> </dependency> <!-- Thymeleaf中使用Shiro标签 --> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
yml configuration
server:
port: 9999
servlet:
session:
# Let Tomcat only obtain session information from COOKIE, In this way, when there is no cookie, the URL will not be automatically added;jsessionid=….
tracking-modes: COOKIEspring:
thymeleaf:
# Turn off page caching to facilitate development environment testing
cache: false
# Static resource path
prefix : classpath:/templates/
# Default .html ending for web resources is
mode: HTML
Shiro’s three functional modules
Subject
Authentication subject, usually refers to the user (leave the operation to SecurityManager).
SecurityManager
Security manager, security manager, manages all Subjects and can cooperate with internal security components (associated with Realm)
Realm
Domain object is used to verify permission information. It is a bridge between shiro and data. For example, our login verification and permission verification are Realm is defined.
Define the user entity User, which can be defined according to your own business
@Data @Accessors(chain = true) public class User { /** * 用户id */ private Long userId; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 用户别称 */ private String name; }
Rewrite the login verification doGetAuthenticationInfo and authorization doGetAuthorizationInfo methods in AuthorizingRealm, write us Customized verification logic.
/** * 自定义登录授权 * * @author ding */ public class UserRealm extends AuthorizingRealm { /** * 授权 * 此处权限授予 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 在这里为每一个用户添加vip权限 info.addStringPermission("vip"); return info; } /** * 认证 * 此处实现我们的登录逻辑,如账号密码验证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 获取到token UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; // 从token中获取到用户名和密码 String username = token.getUsername(); String password = String.valueOf(token.getPassword()); // 为了方便,这里模拟获取用户 User user = this.getUser(); if (!user.getUsername().equals(username)) { throw new UnknownAccountException("用户不存在"); } else if (!user.getPassword().equals(password)) { throw new IncorrectCredentialsException("密码错误"); } // 校验完成后,此处我们把用户信息返回,便于后面我们通过Subject获取用户的登录信息 return new SimpleAuthenticationInfo(user, password, getName()); } /** * 此处模拟用户数据 * 实际开发中,换成数据库查询获取即可 */ private User getUser() { return new User() .setName("admin") .setUserId(1L) .setUsername("admin") .setPassword("123456"); } }
ShiroConfig.java
/**
* Shiro has built-in filters that can implement interceptors related to interceptors
* Frequently used filters:
* anon: No need for authentication (login) to access
* authc: Authentication is required to access
* user: If you use the rememberMe function, you can directly access
* perms: The resource must obtain resource permissions before it can be accessed, format perms[permission 1,permission 2]
* role: This resource must obtain role permission before it can access
**/
/** * shiro核心管理器 * * @author ding */ @Configuration public class ShiroConfig { /** * 无需认证就可以访问 */ private final static String ANON = "anon"; /** * 必须认证了才能访问 */ private final static String AUTHC = "authc"; /** * 拥有对某个资源的权限才能访问 */ private final static String PERMS = "perms"; /** * 创建realm,这里返回我们上一把定义的UserRealm */ @Bean(name = "userRealm") public UserRealm userRealm() { return new UserRealm(); } /** * 创建安全管理器 */ @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //绑定realm对象 securityManager.setRealm(userRealm); return securityManager; } /** * 授权过滤器 */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); // 设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); // 添加shiro的内置过滤器 Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/index", ANON); filterMap.put("/userInfo", PERMS + "[vip]"); filterMap.put("/table2", AUTHC); filterMap.put("/table3", PERMS + "[vip2]"); bean.setFilterChainDefinitionMap(filterMap); // 设置跳转登陆页 bean.setLoginUrl("/login"); // 无权限跳转 bean.setUnauthorizedUrl("/unAuth"); return bean; } /** * Thymeleaf中使用Shiro标签 */ @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } }
IndexController.java
/** * @author ding */ @Controller public class IndexController { @RequestMapping({"/", "/index"}) public String index(Model model) { model.addAttribute("msg", "hello,shiro"); return "/index"; } @RequestMapping("/userInfo") public String table1(Model model) { return "userInfo"; } @RequestMapping("/table") public String table(Model model) { return "table"; } @GetMapping("/login") public String login() { return "login"; } @PostMapping(value = "/doLogin") public String doLogin(@RequestParam("username") String username, @RequestParam("password") String password, Model model) { //获取当前的用户 Subject subject = SecurityUtils.getSubject(); //用来存放错误信息 String msg = ""; //如果未认证 if (!subject.isAuthenticated()) { //将用户名和密码封装到shiro中 UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { // 执行登陆方法 subject.login(token); } catch (Exception e) { e.printStackTrace(); msg = "账号或密码错误"; } //如果msg为空,说明没有异常,就返回到主页 if (msg.isEmpty()) { return "redirect:/index"; } else { model.addAttribute("errorMsg", msg); return "login"; } } return "/login"; } @GetMapping("/logout") public String logout() { SecurityUtils.getSubject().logout(); return "index"; } @GetMapping("/unAuth") public String unAuth() { return "unAuth"; } }
Create templates folder in resources to store page resources
index.html
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <html xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h2>首页</h2> <!-- 使用shiro标签 --> <shiro:authenticated> <p>用户已登录</p> <a th:href="@{/logout}" rel="external nofollow" >退出登录</a> </shiro:authenticated> <shiro:notAuthenticated> <p>用户未登录</p> </shiro:notAuthenticated> <br/> <a th:href="@{/userInfo}" rel="external nofollow" >用户信息</a> <a th:href="@{/table}" rel="external nofollow" >table</a> </body> </html>
login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>登陆页</title> </head> <body> <div> <p th:text="${errorMsg}"></p> <form action="/doLogin" method="post"> <h3>登陆页</h3> <h7>账号:admin,密码:123456</h7> <input type="text" id="username" name="username" placeholder="admin"> <input type="password" id="password" name="password" placeholder="123456"> <button type="submit">登陆</button> </form> </div> </body> </html>
userInfo.html
<!DOCTYPE html> <html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> <head> <meta charset="UTF-8"> <title>table1</title> </head> <body> <h2>用户信息</h2> <!-- 利用shiro获取用户信息 --> 用户名:<shiro:principal property="username"/> <br/> 用户完整信息: <shiro:principal/> </body> </html>
table.hetml
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>table</title> </head> <body> <h2>table</h2> </body> </html>
Start project browser input127.0.0.1:9999
When we click on the user information and table, the login page will automatically jump
After successful login
Get user information
What we get here is the user information returned by our previous doGetAuthenticationInfo method, here for demonstration All are returned. In actual production, the password cannot be returned.
The above is the detailed content of How Springboot integrates Shiro to implement login and permission verification. For more information, please follow other related articles on the PHP Chinese website!