最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄功能(多 Realm 認(rèn)證)

 更新時(shí)間:2021年02月26日 11:05:06   作者:風(fēng)青宇  
這篇文章主要介紹了SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄(多 Realm 認(rèn)證),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

導(dǎo)入依賴(pom.xml)

 <!--整合Shiro安全框架-->
  <dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.4.0</version>
  </dependency>
  <!--集成jwt實(shí)現(xiàn)token認(rèn)證-->
  <dependency>
   <groupId>com.auth0</groupId>
   <artifactId>java-jwt</artifactId>
   <version>3.2.0</version>
  </dependency>

在 SpringBoot 項(xiàng)目配置 config 包下創(chuàng)建 ShiroConfig 配置類

@Configuration
public class ShiroConfig {

 /**
  * ShiroFilterFactoryBean
  * <p>
  * anon:無需認(rèn)證就可以訪問
  * authc:必須認(rèn)證才能訪問
  * user:必須擁有 記住我 功能才能用
  * perms:擁有對(duì)某個(gè)資源的權(quán)限能訪問
  * role:擁有某個(gè)角色權(quán)限能訪問
  */
 @Bean
 public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
  ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
  // 設(shè)置安全管理器
  factoryBean.setSecurityManager(defaultWebSecurityManager);
  // 添加shiro的內(nèi)置過濾器
  Map<String, String> filterMap = new LinkedHashMap<>();
  // 放行不需要權(quán)限認(rèn)證的接口
  // 網(wǎng)站首頁
  filterMap.put("/", "anon");
  filterMap.put("/index", "anon");
  filterMap.put("/index.html", "anon");
  // 不驗(yàn)證跳轉(zhuǎn)接口
  filterMap.put("/into/**", "anon");

  // 需要權(quán)限認(rèn)證的接口
  // 驗(yàn)證跳轉(zhuǎn)接口
  filterMap.put("/verifyInto/**", "authc");
  
  factoryBean.setFilterChainDefinitionMap(filterMap);

  // 訪問沒有授權(quán)的資源
  factoryBean.setLoginUrl("redirect:/into/login");
  // 設(shè)置無權(quán)限時(shí)跳轉(zhuǎn)的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();
 }

 /**
  * 注入 郵箱驗(yàn)證登錄EmailRealm
  */
 @Bean
 @DependsOn("lifecycleBeanPostProcessor")
 public UserEmailRealm userEmailRealm() {
  return new UserEmailRealm();
 }

 /**
  * 默認(rèn)安全管理器
  */
 @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;
 }

 /**
  * 認(rèn)證器 把我們的自定義驗(yàn)證加入到認(rèn)證器中
  */
 @Bean
 public AbstractAuthenticator abstractAuthenticator(UserPasswordRealm userPasswordRealm, UserEmailRealm userEmailRealm) {
  // 自定義模塊化認(rèn)證器,用于解決多realm拋出異常問題
  //開始沒用自定義異常問題,發(fā)現(xiàn)不管是賬號(hào)密碼錯(cuò)誤還是什么錯(cuò)誤
  //shiro只會(huì)拋出一個(gè)AuthenticationException異常
  ModularRealmAuthenticator authenticator = new MyCustomModularRealmAuthenticator();
  // 認(rèn)證策略:AtLeastOneSuccessfulStrategy(默認(rèn)),AllSuccessfulStrategy,F(xiàn)irstSuccessfulStrategy
  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注解 切點(diǎn)
  */
 @Bean
 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
  AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
  return authorizationAttributeSourceAdvisor;
 }

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

 /**
  * 設(shè)置cookie有效時(shí)間
  */
 @Bean
 public SimpleCookie rememberMeCookie() {
  /*這個(gè)參數(shù)是cookie的名稱,對(duì)應(yīng)前端頁面的checkbox的name=remremberMe*/
  SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
  /*cookie的有效時(shí)間為30天,單位秒*/
  simpleCookie.setMaxAge(259200);
  return simpleCookie;
 }

}

創(chuàng)建自定義驗(yàn)證器 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;
 }
}

創(chuàng)建密碼登錄時(shí)驗(yàn)證授權(quán) UserPasswordRealm 類

@Component
public class UserPasswordRealm extends AuthorizingRealm {

 // 注入用戶業(yè)務(wù)
 @Autowired
 private UserMapper userMapper;

 /**
  * 授權(quán)
  */
 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  System.out.println("————密碼授權(quán)————doGetAuthorizationInfo————");

  return null;
 }

 /**
  * 認(rèn)證
  */
 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  System.out.println("————密碼認(rèn)證————doGetAuthenticationInfo————");

  UsernamePasswordToken userToken = (UsernamePasswordToken) token;
  // 連接數(shù)據(jù)庫 查詢用戶數(shù)據(jù)
  QueryWrapper<User> wrapper = new QueryWrapper<>();
  wrapper.eq("user_name", userToken.getUsername());
  User user = userMapper.selectOne(wrapper);
  // 驗(yàn)證用戶
  if (user == null) {
   throw new UnknownAccountException();
  }
  return new SimpleAuthenticationInfo("", user.getUserPassword(), "");
 }

 /**
  * 用來判斷是否使用當(dāng)前的 realm
  *
  * @param var1 傳入的token
  * @return true就使用,false就不使用
  */
 @Override
 public boolean supports(AuthenticationToken var1) {
  return var1 instanceof UsernamePasswordToken;
 }

}

創(chuàng)建郵件驗(yàn)證碼登錄時(shí)驗(yàn)證授權(quán)UserEmailRealm

@Component
public class UserEmailRealm extends AuthorizingRealm {

 // 注入用戶業(yè)務(wù)
 @Autowired
 UserService userService;

 @Override
 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  System.out.println("————郵箱登錄授權(quán)————doGetAuthorizationInfo————");
  return null;
 }

 @Override
 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  System.out.println("————郵箱登錄認(rèn)證————doGetAuthenticationInfo————");
  UserEmailToken userEmailToken = (UserEmailToken) token;
  String userEmail = (String) userEmailToken.getPrincipal();
  // 連接數(shù)據(jù)庫 查詢用戶數(shù)據(jù)
  QueryWrapper<User> wrapper = new QueryWrapper<>();
  wrapper.eq("user_email", userEmail);
  User user = userService.getOne(wrapper);
  //因?yàn)闆]有密碼,并且驗(yàn)證碼在之前就驗(yàn)證了
  if (user == null) {
   throw new UnknownAccountException();
  }
  return new SimpleAuthenticationInfo("", userEmail, "");
 }

 /**
  * 用來判斷是否使用當(dāng)前的 realm
  *
  * @param var1 傳入的token
  * @return true就使用,false就不使用
  */
 @Override
 public boolean supports(AuthenticationToken var1) {
  return var1 instanceof UserEmailToken;
 }
}

創(chuàng)建郵件驗(yàn)證碼登錄驗(yàn)證通過生成令牌的 UserEmailToken 類(密碼登錄時(shí)使用shiro默認(rèn)的 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;
 }
}

創(chuàng)建密碼鹽值加密 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; // 加密次數(shù)
  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) {
  // 獲取當(dāng)前的用戶
  Subject subject = SecurityUtils.getSubject();
  // 對(duì)密碼進(jìn)行MD5鹽值加密
  String md5Password = new MDPasswordUtil().getMDPasswordUtil(userName, userPassword);
  // 封裝用戶的登錄數(shù)據(jù)
  UsernamePasswordToken token = new UsernamePasswordToken(userName, md5Password);
  //rememberme記住我
  token.setRememberMe(true);
  try {
   // 登錄,驗(yàn)證,保存令牌
   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", "用戶名錯(cuò)誤!請重新輸入。");
   return "login";
  } catch (IncorrectCredentialsException ice) {
   model.addAttribute("pwError", "密碼錯(cuò)誤!請重新輸入。");
   return "login";
  }
 }

控制層用戶郵件驗(yàn)證碼密碼登錄

// 用戶郵箱登錄
 @PostMapping("/emailLogin")
 public String emailLogin(@RequestParam("userEmail") String userEmail,
        @RequestParam("emailCode") String emailCode,
        HttpSession session, Model model) {
  // 根據(jù)userEmail從session中取出發(fā)送的驗(yàn)證碼
  String sendEmailCode = (String) session.getAttribute(userEmail);
  // 比對(duì)驗(yàn)證碼
  if (StringUtils.isNoneBlank(sendEmailCode) && sendEmailCode.equals(emailCode)) {
   try {
    UserEmailToken token = new UserEmailToken(userEmail);
    //rememberme記住我
    token.setRememberMe(true);
    // 登錄,驗(yàn)證,保存令牌
    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);

    // 銷毀驗(yàn)證碼
    session.removeAttribute(emailCode);

    return "admin";
   } catch (Exception e) {
    model.addAttribute("error", "驗(yàn)證碼錯(cuò)誤!請重新輸入。");
    return "login";
   }
  } else {
   return "login";
  }
 }

SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄(多 Realm 認(rèn)證)就可以了 (有點(diǎn)多,哈哈哈)

推薦大神:狂神說Java

到此這篇關(guān)于SpringBoot 整合 Shiro 密碼登錄與郵件驗(yàn)證碼登錄(多 Realm 認(rèn)證)的文章就介紹到這了,更多相關(guān)SpringBoot 整合 Shiro登錄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA Calendar類使用方面實(shí)例

    JAVA Calendar類使用方面實(shí)例

    這篇文章主要介紹了JAVA Calendar類使用方面實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Java二叉樹中LCA問題解決方法兩則

    Java二叉樹中LCA問題解決方法兩則

    這篇文章主要介紹了Java二叉樹中LCA問題解決方法,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路
    2022-12-12
  • 基于Hibernate中配置文件的學(xué)習(xí)(分享)

    基于Hibernate中配置文件的學(xué)習(xí)(分享)

    下面小編就為大家?guī)硪黄贖ibernate中配置文件的學(xué)習(xí)(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Maven繼承父工程時(shí)的relativePath標(biāo)簽解析用法小結(jié)

    Maven繼承父工程時(shí)的relativePath標(biāo)簽解析用法小結(jié)

    relativePath 的作用是為了找到父級(jí)工程的pom.xml,本文主要介紹了Maven繼承父工程時(shí)的relativePath標(biāo)簽解析用法小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • Java不指定長度的二維數(shù)組實(shí)例

    Java不指定長度的二維數(shù)組實(shí)例

    今天小編就為大家分享一篇Java不指定長度的二維數(shù)組實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • 解決阿里代碼規(guī)范檢測中方法缺少javadoc注釋的問題

    解決阿里代碼規(guī)范檢測中方法缺少javadoc注釋的問題

    這篇文章主要介紹了解決阿里代碼規(guī)范檢測中方法缺少javadoc注釋的問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Mapper層繼承BaseMapper<T>需要引入的pom依賴方式

    Mapper層繼承BaseMapper<T>需要引入的pom依賴方式

    這篇文章主要介紹了Mapper層繼承BaseMapper<T>需要引入的pom依賴方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • JDK8?HashMap擴(kuò)容算法demo

    JDK8?HashMap擴(kuò)容算法demo

    這篇文章主要為大家介紹了JDK8?HashMap擴(kuò)容算法demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 使用Easyexcel實(shí)現(xiàn)不同場景的數(shù)據(jù)導(dǎo)出功能

    使用Easyexcel實(shí)現(xiàn)不同場景的數(shù)據(jù)導(dǎo)出功能

    這篇文章主要為大家詳細(xì)介紹了如何在不同場景下使用Easyexcel實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • JAVA String轉(zhuǎn)化成java.sql.date和java.sql.time方法示例

    JAVA String轉(zhuǎn)化成java.sql.date和java.sql.time方法示例

    這篇文章主要給大家分享了關(guān)于JAVA String轉(zhuǎn)化成java.sql.date和java.sql.time的方法,文中給出了詳細(xì)的示例代碼,相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。
    2017-03-03

最新評(píng)論

纳雍县| 巴楚县| 闻喜县| 南雄市| 金昌市| 札达县| 荆门市| 贺兰县| 平潭县| 乌审旗| 琼海市| 三原县| 和平县| 达州市| 开原市| 漳浦县| 白水县| 香河县| 金平| 启东市| 鄄城县| 灵川县| 嵩明县| 绿春县| 黄石市| 方山县| 从江县| 绥滨县| 克拉玛依市| 班玛县| 景泰县| 咸阳市| 宿松县| 怀安县| 九寨沟县| 阳西县| 娱乐| 永川市| 布尔津县| 新干县| 泾阳县|