SpringBoot 整合 Shiro 密码登录与邮件验证码登录功能(多 Realm 认证)

导入依赖(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 配置类

@Configuration
public class ShiroConfig {

 /**
  * ShiroFilterFactoryBean
  * <p>
  * anon:无需认证就可以访问
  * authc:必须认证才能访问
  * user:必须拥有 记住我 功能才能用
  * perms:拥有对某个资源的权限能访问
  * role:拥有某个角色权限能访问
  */
 @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/**", "anon");

  // 需要权限认证的接口
  // 验证跳转接口
  filterMap.put("/verifyInto/**", "authc");

  factoryBean.setFilterChainDefinitionMap(filterMap);

  // 访问没有授权的资源
  factoryBean.setLoginUrl("redirect:/into/login");
  // 设置无权限时跳转的url
  factoryBean.setUnauthorizedUrl("redirect:/into/login");

  return factoryBean;
 }

 /**
  * 管理shiro的生命周期
  */
 @Bean("lifecycleBeanPostProcessor")
 public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
  return new LifecycleBeanPostProcessor();
 }

 /**
  * 注入 密码登录CustomRealm
  */
 @Bean
 @DependsOn("lifecycleBeanPostProcessor")
 public UserPasswordRealm userPasswordRealm() {
  return new UserPasswordRealm();
 }

 /**
  * 注入 邮箱验证登录EmailRealm
  */
 @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;
 }

 /**
  * 加入shiro注解 代理生成器 切面
  */
 @Bean
 @DependsOn({"lifecycleBeanPostProcessor"})
 public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
  DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
  advisorAutoProxyCreator.setProxyTargetClass(true);
  return advisorAutoProxyCreator;
 }

 /**
  * 加入shiro注解 切点
  */
 @Bean
 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
  AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
  return authorizationAttributeSourceAdvisor;
 }

 /**
  * 设置cookie 记住我生成cookie
  */
 @Bean
 public CookieRememberMeManager cookieRememberMeManager() {
  CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
  cookieRememberMeManager.setCookie(rememberMeCookie());
  return cookieRememberMeManager;
 }

 /**
  * 设置cookie有效时间
  */
 @Bean
 public SimpleCookie rememberMeCookie() {
  /*这个参数是cookie的名称,对应前端页面的checkbox的name=remremberMe*/
  SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
  /*cookie的有效时间为30天,单位秒*/
  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 类

@Component
public 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(), "");
 }

 /**
  * 用来判断是否使用当前的 realm
  *
  * @param var1 传入的token
  * @return true就使用,false就不使用
  */
 @Override
 public boolean supports(AuthenticationToken var1) {
  return var1 instanceof UsernamePasswordToken;
 }

}

创建邮件验证码登录时验证授权UserEmailRealm

@Component
public 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, "");
 }

 /**
  * 用来判断是否使用当前的 realm
  *
  * @param var1 传入的token
  * @return true就使用,false就不使用
  */
 @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;
 }

 /**
  * 重写getPrincipal方法
  */
 @Override
 public Object getPrincipal() {
  return userEmail;
 }

 /**
  * 重写getCredentials方法
  */
 @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";
  }
 }

SpringBoot 整合 Shiro 密码登录与邮件验证码登录(多 Realm 认证)就可以了 (有点多,哈哈哈)

推荐大神:狂神说Java

到此这篇关于SpringBoot 整合 Shiro 密码登录与邮件验证码登录(多 Realm 认证)的文章就介绍到这了,更多相关SpringBoot 整合 Shiro登录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot整合Shiro实现登录认证的方法

    安全无处不在,趁着放假读了一下 Shiro 文档,并记录一下 Shiro 整合 Spring Boot 在数据库中根据角色控制访问权限 简介 Apache Shiro是一个功能强大.灵活的,开源的安全框架.它可以干净利落地处理身份验证.授权.企业会话管理和加密. 上图是 Shiro 的基本架构 Authentication(认证) 有时被称为"登录",用来证明用户是用户他们自己本人 Authorization(授权) 访问控制的过程,即确定"谁"访问"什么

  • SpringBoot 整合 Shiro 密码登录的实现代码

    导入依赖(pom.xml) <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!--集成jwt实现token认证--> <dependency

  • springboot整合shiro登录失败次数限制功能的实现代码

    这次讲讲如何限制用户登录尝试次数,防止坏人多次尝试,恶意暴力破解密码的情况出现,要限制用户登录尝试次数,必然要对用户名密码验证失败做记录,Shiro中用户名密码的验证交给了CredentialsMatcher 所以在CredentialsMatcher里面检查,记录登录次数是最简单的做法.当登录失败次数达到限制,修改数据库中的状态字段,并返回前台错误信息.  因为之前的博客都是用的明文,这里就不对密码进行加密了,如果有需要加密,将自定义密码比较器从SimpleCredentialsMatcher

  • SpringBoot+Shiro学习之密码加密和登录失败次数限制示例

    这个项目写到现在,基本的雏形出来了,在此感谢一直关注的童鞋,送你们一句最近刚学习的一句鸡汤:念念不忘,必有回响.再贴一张ui图片: 前篇思考问题解决 前篇我们只是完成了同一账户的登录人数限制shiro拦截器的编写,对于手动踢出用户的功能只是说了采用在session域中添加一个key为kickout的布尔值,由之前编写的KickoutSessionControlFilter拦截器来判断是否将用户踢出,还没有说怎么获取当前在线用户的列表的核心代码,下面贴出来: /** * <p> * 服务实现类

  • 基于springboot实现整合shiro实现登录认证以及授权过程解析

    这篇文章主要介绍了基于springboot实现整合shiro实现登录认证以及授权过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.添加shiro的依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web- starter</artifactId> <version&g

  • Springboot+Shiro记录用户登录信息并获取当前登录用户信息的实现代码

    由于最近做项目需要,在用户登陆后有一个功能是需要用户的信息,进行写入数据库的操作.但是目前还用不到Shiro的高级权限,只为了简单获取用户信息,自己整合了一个只记录用户,获取用户信息的功能. 导入Shiro依赖 <!-- Shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version

  • SpringBoot 整合 Shiro 密码登录与邮件验证码登录功能(多 Realm 认证)

    导入依赖(pom.xml) <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!--集成jwt实现token认证--> <dependency

  • springboot整合shiro多验证登录功能的实现(账号密码登录和使用手机验证码登录)

    1. 首先新建一个shiroConfig shiro的配置类,代码如下: @Configuration public class SpringShiroConfig { /** * @param realms 这儿使用接口集合是为了实现多验证登录时使用的 * @return */ @Bean public SecurityManager securityManager(Collection<Realm> realms) { DefaultWebSecurityManager sManager

  • springboot整合shiro实现登录验证授权的过程解析

    springboot整合shiro实现登录验证授权,内容如下所示: 1.添加依赖: <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.7.1</version> </dependency> 2.yml配置: #配置服务端口 s

  • Springboot整合Shiro实现登录与权限校验详细解读

    目录 Springboot-cli 开发脚手架系列 简介 前言 1. 环境 2. 简介 3. Realm配置 4. 核心配置 5. 接口编写 6. 网页资源 7. 效果演示 8. 源码分享 Springboot-cli 开发脚手架系列 Springboot优雅的整合Shiro进行登录校验,权限认证(附源码下载) 简介 Springboo配置Shiro进行登录校验,权限认证,附demo演示. 前言 我们致力于让开发者快速搭建基础环境并让应用跑起来,提供使用示例供使用者参考,让初学者快速上手. 本博

  • SpringBoot整合Shiro的代码详解

    shiro是一个权限框架,具体的使用可以查看其官网 http://shiro.apache.org/  它提供了很方便的权限认证和登录的功能. 而springboot作为一个开源框架,必然提供了和shiro整合的功能!接下来就用springboot结合springmvc,mybatis,整合shiro完成对于用户登录的判定和权限的验证. 1.准备数据库表结构 这里主要涉及到五张表:用户表,角色表(用户所拥有的角色),权限表(角色所涉及到的权限),用户-角色表(用户和角色是多对多的),角色-权限表

  • springboot整合shiro与自定义过滤器的全过程

    目录 filter自定义过滤器  增加了 对验证码的校验 Shiro中的权限控制 总结 filter自定义过滤器  增加了 对验证码的校验 package com.youxiong.filter; import com.youxiong.shiro.UsernamePasswordKaptchaToken; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.subject.Subject; imp

  • SpringBoot整合Shiro思路(最新超详细)

    目录 1.SpringBoot整合Shiro思路 2.环境搭建 2.1创建项目 2.2引入依赖 2.3创建前端页面 2.4配置视图信息 2.5解决IDEA冲突问题 2.6测试搭建的环境 3.整合Shiro 3.1引入依赖 3.2自定义Realm 3.3Shiro配置 3.4启动测试 4.常见过滤器 5.认证和退出 5.1在index.jsp添加a标签 5.2编写controller 5.3修改自定义Realm 5.4修改ShiroConfig配置 5.5测试 6.MDSalt的认证实现 6.1创

  • Springboot整合Shiro的代码实例

    这篇文章主要介绍了Springboot整合Shiro的代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.导入依赖 <!--shiro--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</versio

  • Springboot 整合shiro实现权限控制的方法

    Author:jeffrey Date:2019-04-08 一.开发环境: 1.mysql - 5.7 2.navicat(mysql客户端管理工具) 3.idea 2017.2 4.jdk8 5.tomcat 8.5 6.springboot2.1.3 7.mybatis 3 8.shiro1.4 9.maven3.3.9 二.数据库设计 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CB46ByC1-1604249108144)(img/shiro01.pn

随机推荐