背景:
上文学习了shrio 基本概念后,本章将进一步的落地实践学习,在springboot中如何去整合shrio,整个过程步骤有个清晰的了解。
利用Shiro进行登录认证主要步骤:
1. 添加依赖:首先,在pom.xml
文件中添加Spring Boot和Shiro的相关依赖。
<!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency>
2. 创建Shiro配置类:创建一个ShiroConfig
类,用于配置Shiro的相关信息和组件。(对于配置的解释和作用见第三章杂谈)
@Configuration public class ShiroConfig { // 配置安全管理器 @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm()); return securityManager; } // 配置自定义Realm @Bean public MyRealm myRealm() { return new MyRealm(); } // 配置Shiro过滤器 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean() { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager()); shiroFilterFactoryBean.setLoginUrl("/login"); // 设置登录页面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); // 设置未授权页面 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 允许匿名访问的路径 filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/static/**", "anon"); // 需要认证才能访问的路径 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } }
3. 创建自定义Realm:创建一个MyRealm
类,继承AuthorizingRealm
并实现相关方法,用于处理认证和授权逻辑
public class MyRealm extends AuthorizingRealm { // 处理认证逻辑 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 从token中获取用户名 String username = (String) authenticationToken.getPrincipal(); // 模拟从数据库或其他存储中获取用户信息 // 例如,从数据库中查询用户信息并返回 String dbPassword = "123456"; // 假设从数据库中查询的密码是123456 // 返回认证信息,包括用户名和密码 return new SimpleAuthenticationInfo(username, dbPassword, getName()); } // 处理授权逻辑 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 从PrincipalCollection中获取用户名 String username = (String) principalCollection.getPrimaryPrincipal(); // 模拟从数据库或其他存储中获取用户角色和权限信息 // 例如,从数据库中查询用户对应的角色和权限并返回 Set<String> roles = new HashSet<>(); roles.add("admin"); // 假设用户拥有admin角色 Set<String> permissions = new HashSet<>(); permissions.add("user:read"); // 假设用户拥有user:read权限 // 创建授权信息 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(permissions); return authorizationInfo; } }
4. 创建登录接口和登录页面:创建一个登录接口处理用户的登录请求
@Controller public class LoginController { @GetMapping("/login") public String login() { return "login"; } @PostMapping("/login") public String doLogin(String username, String password) { // 执行登录逻辑 Subject currentUser = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { currentUser.login(token); // 执行登录 return "redirect:/home"; // 登录成功后跳转到首页 } catch (AuthenticationException e) { return "redirect:/login-error"; // 登录失败后跳转到错误页面 } } }
整体的执行流程:
-
用户在浏览器中访问登录页面,输入用户名和密码,并点击登录按钮。
-
Controller层的
LoginController
类中的doLogin
方法被调用,该方法接收用户名和密码作为参数。 -
创建一个
Subject
对象,该对象代表当前正在与应用程序交互的用户。 -
创建一个
UsernamePasswordToken
对象,将用户名和密码设置为该对象的属性。 -
调用
Subject
对象的login
方法,将UsernamePasswordToken
对象作为参数传递进去。 -
Subject
对象将UsernamePasswordToken
对象传递给Shiro进行认证。 -
Shiro框架会调用
MyRealm
类中的doGetAuthenticationInfo
方法,该方法用于处理认证逻辑。 -
在
doGetAuthenticationInfo
方法中,从UsernamePasswordToken
对象中获取用户名。 -
可以根据需要,从数据库或其他存储中获取与用户名对应的用户信息,例如密码等。
-
将获取到的用户信息与
UsernamePasswordToken
对象中的密码进行比较,判断用户是否通过认证。 -
如果认证成功,创建一个
SimpleAuthenticationInfo
对象,将用户名、数据库中的密码和Realm名称作为参数传递给它。 -
SimpleAuthenticationInfo
对象会被返回给Shiro框架,表示认证成功。 -
Shiro框架会将认证成功的信息保存在
Subject
对象中。 -
如果认证失败,将抛出
AuthenticationException
异常。 -
在
doLogin
方法中,通过捕获AuthenticationException
异常,可以处理登录失败的情况,例如重定向到登录失败页面。 -
如果登录成功,可以根据需要执行一些操作,例如重定向到首页或其他需要登录后才能访问的页面。
总结起来,整个执行流程如下:
- 用户输入用户名和密码,并提交登录表单。
- Controller层的
LoginController
类中的doLogin
方法接收到登录请求。 - 创建
Subject
对象,代表当前用户。 - 创建
UsernamePasswordToken
对象,将用户名和密码设置为其属性。 - 调用
Subject
对象的login
方法,将UsernamePasswordToken
对象作为参数传入。 - Shiro框架调用
MyRealm
类中的doGetAuthenticationInfo
方法,处理认证逻辑。 - 在
doGetAuthenticationInfo
方法中,获取用户名和密码,并与数据库中的信息进行比较。 - 如果认证成功,返回一个
SimpleAuthenticationInfo
对象,表示认证通过。 - 如果认证失败,抛出
AuthenticationException
异常。 - 在
doLogin
方法中,根据认证结果执行相应的操作,例如重定向到登录成功页面或登录失败页面。