如何在SpringBoot中使用shiro怎么实现一个邮件验证码登录功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。导入依赖(pom.xml) &
如何在SpringBoot中使用shiro怎么实现一个邮件验证码登录功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
导入依赖(pom.xml)
<!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!--集成Jwt实现token认证--> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.2.0</version> </dependency>
在 SpringBoot 项目配置 config 包下创建 ShiroConfig 配置类
@Configurationpublic class ShiroConfig { @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWEBSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); // 设置安全管理器 factoryBean.setSecurityManager(defaultWebSecurityManager); // 添加shiro的内置过滤器 Map<String, String> filterMap = new LinkedHashMap<>(); // 放行不需要权限认证的接口 // 网站首页 filterMap.put("/", "anon"); filterMap.put("/index", "anon"); filterMap.put("/index.html", "anon"); // 不验证跳转接口 filterMap.put("/into @Bean("lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean @DependsOn("lifecycleBeanPostProcessor") public UserPassWordRealm userPasswordRealm() { return new UserPasswordRealm(); } @Bean @DependsOn("lifecycleBeanPostProcessor") public UserEmailRealm userEmailRealm() { return new UserEmailRealm(); } @Bean public DefaultWebSecurityManager securityManager(UserPasswordRealm userPasswordRealm, UserEmailRealm userEmailRealm, AbstractAuthenticator abstractAuthenticator) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); List<Realm> realms = new ArrayList<>(); realms.add(userPasswordRealm); realms.add(userEmailRealm); defaultWebSecurityManager.setRealms(realms); // 记住我 defaultWebSecurityManager.setRememberMeManager(cookieRememberMeManager()); defaultWebSecurityManager.setAuthenticator(abstractAuthenticator); return defaultWebSecurityManager; } @Bean public AbstractAuthenticator abstractAuthenticator(UserPasswordRealm userPasswordRealm, UserEmailRealm userEmailRealm) { // 自定义模块化认证器,用于解决多realm抛出异常问题 //开始没用自定义异常问题,发现不管是账号密码错误还是什么错误 //shiro只会抛出一个AuthenticationException异常 ModularRealmAuthenticator authenticator = new MyCustomModularRealmAuthenticator(); // 认证策略:AtLeastOneSuccessfulStrategy(默认),AllSuccessfulStrategy,FirstSuccessfulStrategy authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy()); // 加入realms List<Realm> realms = new ArrayList<>(); realms.add(userPasswordRealm); realms.add(userEmailRealm); authenticator.setRealms(realms); return authenticator; } @Bean @DependsOn({"lifecycleBeanPostProcessor"}) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean public CookieRememberMeManager cookieRememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); return cookieRememberMeManager; } @Bean public SimpleCookie rememberMeCookie() { SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); simpleCookie.setMaxAge(259200); return simpleCookie; }}
创建自定义验证器 MyCustomModularRealmAuthenticator 类
public class MyCustomModularRealmAuthenticator extends ModularRealmAuthenticator { @Override protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) { AuthenticationStrategy authenticationStrategy = this.getAuthenticationStrategy(); AuthenticationInfo authenticationInfo = authenticationStrategy.beforeAllAttempts(realms, token); Iterator var5 = realms.iterator(); while (var5.hasNext()) { Realm realm = (Realm) var5.next(); authenticationInfo = authenticationStrategy.beforeAttempt(realm, token, authenticationInfo); if (realm.supports(token)) { AuthenticationInfo info = null; Throwable t = null; info = realm.getAuthenticationInfo(token); authenticationInfo = authenticationStrategy.afterAttempt(realm, token, info, authenticationInfo, t); } } authenticationInfo = authenticationStrategy.afterAllAttempts(token, authenticationInfo); return authenticationInfo; }}
创建密码登录时验证授权 UserPasswordRealm 类
@Componentpublic class UserPasswordRealm extends AuthorizingRealm { // 注入用户业务 @Autowired private UserMapper userMapper; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("————密码授权————doGetAuthorizationInfo————"); return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("————密码认证————doGetAuthenticationInfo————"); UsernamePasswordToken userToken = (UsernamePasswordToken) token; // 连接数据库 查询用户数据 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("user_name", userToken.getUsername()); User user = userMapper.selectOne(wrapper); // 验证用户 if (user == null) { throw new UnknownAccountException(); } return new SimpleAuthenticationInfo("", user.getUserPassword(), ""); } @Override public boolean supports(AuthenticationToken var1) { return var1 instanceof UsernamePasswordToken; }}
创建邮件验证码登录时验证授权UserEmailRealm 类
@Componentpublic class UserEmailRealm extends AuthorizingRealm { // 注入用户业务 @Autowired UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("————邮箱登录授权————doGetAuthorizationInfo————"); return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("————邮箱登录认证————doGetAuthenticationInfo————"); UserEmailToken userEmailToken = (UserEmailToken) token; String userEmail = (String) userEmailToken.getPrincipal(); // 连接数据库 查询用户数据 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("user_email", userEmail); User user = userService.getOne(wrapper); //因为没有密码,并且验证码在之前就验证了 if (user == null) { throw new UnknownAccountException(); } return new SimpleAuthenticationInfo("", userEmail, ""); } @Override public boolean supports(AuthenticationToken var1) { return var1 instanceof UserEmailToken; }}
创建邮件验证码登录验证通过生成令牌的 UserEmailToken 类(密码登录时使用shiro默认的 UsernamePasswordToken 令牌)
@Data // 使用lombok 生成get方法、set方法public class UserEmailToken implements HostAuthenticationToken, RememberMeAuthenticationToken { private String userEmail; private boolean rememberMe; private String host; public UserEmailToken() { this.rememberMe = false; } public UserEmailToken(String userEmail) { this(userEmail, false, null); } public UserEmailToken(String userEmail, boolean rememberMe) { this(userEmail, rememberMe, null); } public UserEmailToken(String userEmail, boolean rememberMe, String host) { this.userEmail = userEmail; this.rememberMe = rememberMe; this.host = host; } @Override public String getHost() { return host; } @Override public boolean isRememberMe() { return rememberMe; } @Override public Object getPrincipal() { return userEmail; } @Override public Object getCredentials() { return userEmail; }}
创建密码盐值加密 MDPasswordUtil 工具类
public class MDPasswordUtil { public String getMDPasswordUtil(String userName, String userPassword) { String hashAlGorithmName = "MD5"; // 加密方式:md5加密 Object credentials = userPassword; // 密码 Object salt = ByteSource.Util.bytes(userName); // 盐 int hashIterations = 512; // 加密次数 Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); return result.toString(); }}
控制层用户密码登录
// 用户密码登录 @PostMapping("/passwordLogin") public String userLogin(@RequestParam("userName") String userName, @RequestParam("userPassword") String userPassword, httpsession session, Model model) { // 获取当前的用户 Subject subject = SecurityUtils.getSubject(); // 对密码进行MD5盐值加密 String md5Password = new MDPasswordUtil().getMDPasswordUtil(userName, userPassword); // 封装用户的登录数据 UsernamePasswordToken token = new UsernamePasswordToken(userName, md5Password); //rememberme记住我 token.setRememberMe(true); try { // 登录,验证,保存令牌 subject.login(token); //查询登录信息 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("user_name", userName); User user = userService.getOne(wrapper); //保存登录用户信息 session.setAttribute(user.getUserId().toString(), user); return "admin"; } catch (UnknownAccountException e) { model.addAttribute("userError", "用户名错误!请重新输入。"); return "login"; } catch (IncorrectCredentialsException ice) { model.addAttribute("pwError", "密码错误!请重新输入。"); return "login"; } }
控制层用户邮件验证码密码登录
// 用户邮箱登录 @PostMapping("/emailLogin") public String emailLogin(@RequestParam("userEmail") String userEmail, @RequestParam("emailCode") String emailCode, HttpSession session, Model model) { // 根据userEmail从session中取出发送的验证码 String sendEmailCode = (String) session.getAttribute(userEmail); // 比对验证码 if (StringUtils.isNoneBlank(sendEmailCode) && sendEmailCode.equals(emailCode)) { try { UserEmailToken token = new UserEmailToken(userEmail); //rememberme记住我 token.setRememberMe(true); // 登录,验证,保存令牌 Subject subject = SecurityUtils.getSubject(); subject.login(token); //查询登录信息 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("user_email", userEmail); User user = userService.getOne(wrapper); //保存登录用户信息 session.setAttribute(user.getUserId().toString(), user); // 销毁验证码 session.removeAttribute(emailCode); return "admin"; } catch (Exception e) { model.addAttribute("error", "验证码错误!请重新输入。"); return "login"; } } else { return "login"; } }
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网精选频道,感谢您对编程网的支持。
--结束END--
本文标题: 如何在SpringBoot中使用Shiro怎么实现一个邮件验证码登录功能
本文链接: https://www.lsjlt.com/news/247299.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
2024-04-28
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0