SpringBoot Shiro多realm实现免密登录

avatar 2019年01月24日19:44:14 8 12966 views
博主分享免费Java教学视频,B站账号:Java刘哥
  上一篇文章介绍了

SpringBoot整合Shiro,通过用户、角色、权限三者关联实现权限管理

本篇文章主要介绍 Shiro 多 realm,根据不同的登录类型指定不同的 realm。 所谓免密登录,就是区别正常的密码登录。比如,我现在要实现第三方登录,当验证了是张三,现在要让他通过 shiro 的 subject.login(),但是不知道他的密码(密码加密了),我们不能拿数据库里的密码去登录,除非重新写 Realm。 所以需要多个 Realm,一个是密码登录(shiro会根据用户的输入的密码和加密方法加密后比较);一个免密登录(允许使用数据库密码登录,shiro不进行任何加密)。 实现的过程简单说下: 重写 UsernamePasswordToken,加一个 loginType 属性,subject.login() 的时候传入 loginType; 重写 ModularRealmAuthenticator 中的 doAuthenticate() 方法,根据传进来的 loginType 来指定使用哪个 Realm。

一、Shiro 配置

1.两个 Realm NormalRealm.java  密码登录的 Realm
  1. package com.liuyanzhao.sens.config;
  2. import cn.hutool.core.date.DateUnit;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.core.lang.Validator;
  5. import cn.hutool.core.util.ObjectUtil;
  6. import cn.hutool.extra.servlet.ServletUtil;
  7. import cn.hutool.http.HtmlUtil;
  8. import com.liuyanzhao.sens.entity.Permission;
  9. import com.liuyanzhao.sens.entity.Role;
  10. import com.liuyanzhao.sens.entity.User;
  11. import com.liuyanzhao.sens.model.dto.JsonResult;
  12. import com.liuyanzhao.sens.model.dto.LogsRecord;
  13. import com.liuyanzhao.sens.model.enums.CommonParamsEnum;
  14. import com.liuyanzhao.sens.model.enums.ResultCodeEnum;
  15. import com.liuyanzhao.sens.model.enums.TrueFalseEnum;
  16. import com.liuyanzhao.sens.service.PermissionService;
  17. import com.liuyanzhao.sens.service.RoleService;
  18. import com.liuyanzhao.sens.service.UserService;
  19. import com.liuyanzhao.sens.utils.LocaleMessageUtil;
  20. import com.liuyanzhao.sens.utils.Md5Util;
  21. import lombok.extern.slf4j.Slf4j;
  22. import org.apache.commons.lang3.StringUtils;
  23. import org.apache.shiro.authc.*;
  24. import org.apache.shiro.authz.AuthorizationInfo;
  25. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  26. import org.apache.shiro.realm.AuthorizingRealm;
  27. import org.apache.shiro.subject.PrincipalCollection;
  28. import org.apache.shiro.util.ByteSource;
  29. import org.springframework.beans.factory.annotation.Autowired;
  30. import java.util.Date;
  31. import java.util.List;
  32. /**
  33.  * 默认的realm
  34.  *
  35.  * @author 言曌
  36.  * @date 2018/9/1 上午10:47
  37.  */
  38. @Slf4j
  39. public class NormalRealm extends AuthorizingRealm {
  40.     @Autowired
  41.     private UserService userService;
  42.     @Autowired
  43.     private RoleService roleService;
  44.     @Autowired
  45.     private PermissionService permissionService;
  46.     @Autowired
  47.     private LocaleMessageUtil localeMessageUtil;
  48.     /**
  49.      * 认证信息(身份验证) Authentication 是用来验证用户身份
  50.      */
  51.     @Override
  52.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  53.         log.info("认证-->MyShiroRealm.doGetAuthenticationInfo()");
  54.         //1.验证用户名
  55.         User user = null;
  56.         String loginName = (String) token.getPrincipal();
  57.         if (Validator.isEmail(loginName)) {
  58.             user = userService.findByEmail(loginName);
  59.         } else {
  60.             user = userService.findByUserName(loginName);
  61.         }
  62.         if (user == null) {
  63.             //用户不存在
  64.             log.info("用户不存在! 登录名:{}, 密码:{}", loginName, token.getCredentials());
  65.             return null;
  66.         }
  67.         //2.首先判断是否已经被禁用已经是否已经过了10分钟
  68.         Date loginLast = DateUtil.date();
  69.         if (null != user.getLoginLast()) {
  70.             loginLast = user.getLoginLast();
  71.         }
  72.         Long between = DateUtil.between(loginLast, DateUtil.date(), DateUnit.MINUTE);
  73.         if (StringUtils.equals(user.getLoginEnable(), TrueFalseEnum.FALSE.getDesc()) && (between < CommonParamsEnum.TEN.getValue())) {
  74.             log.info("账号已锁定! 登录名:{}, 密码:{}", loginName, token.getCredentials());
  75.             throw new LockedAccountException(localeMessageUtil.getMessage("code.admin.login.disabled"));
  76.         }
  77.         userService.updateUserLoginLast(user, DateUtil.date());
  78.         //3.封装authenticationInfo,准备验证密码
  79.         SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
  80.                 user, // 用户名
  81.                 user.getUserPass(), // 密码
  82.                 ByteSource.Util.bytes("sens"), // 盐
  83.                 getName() // realm name
  84.         );
  85.         System.out.println("realName:" + getName());
  86.         return authenticationInfo;
  87.     }
  88.     @Override
  89.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  90.         log.info("授权-->MyShiroRealm.doGetAuthorizationInfo()");
  91.         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  92.         User user = (User) principals.getPrimaryPrincipal();
  93.         List<Role> roles = roleService.listRolesByUserId(user.getUserId());
  94.         for (Role role : roles) {
  95.             authorizationInfo.addRole(role.getRole());
  96.             List<Permission> permissions = permissionService.listPermissionsByRoleId(role.getId());
  97.             for (Permission p : permissions) {
  98.                 authorizationInfo.addStringPermission(p.getPermission());
  99.             }
  100.         }
  101.         return authorizationInfo;
  102.     }
  103. }
  FreeRealm.java  密码不加密的 Realm
  1. package com.liuyanzhao.sens.config;
  2. import cn.hutool.core.date.DateUnit;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.core.lang.Validator;
  5. import com.liuyanzhao.sens.entity.Permission;
  6. import com.liuyanzhao.sens.entity.Role;
  7. import com.liuyanzhao.sens.entity.User;
  8. import com.liuyanzhao.sens.model.enums.CommonParamsEnum;
  9. import com.liuyanzhao.sens.model.enums.TrueFalseEnum;
  10. import com.liuyanzhao.sens.service.PermissionService;
  11. import com.liuyanzhao.sens.service.RoleService;
  12. import com.liuyanzhao.sens.service.UserService;
  13. import com.liuyanzhao.sens.utils.LocaleMessageUtil;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.apache.commons.lang3.StringUtils;
  16. import org.apache.shiro.authc.*;
  17. import org.apache.shiro.authz.AuthorizationInfo;
  18. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  19. import org.apache.shiro.realm.AuthorizingRealm;
  20. import org.apache.shiro.subject.PrincipalCollection;
  21. import org.apache.shiro.util.ByteSource;
  22. import org.springframework.beans.factory.annotation.Autowired;
  23. import java.util.Date;
  24. import java.util.List;
  25. /**
  26.  * 免密登录,输入的密码和原密码一致
  27.  *
  28.  * @author 言曌
  29.  * @date 2018/9/1 上午10:47
  30.  */
  31. @Slf4j
  32. public class FreeRealm extends AuthorizingRealm {
  33.     @Autowired
  34.     private UserService userService;
  35.     @Autowired
  36.     private RoleService roleService;
  37.     @Autowired
  38.     private PermissionService permissionService;
  39.     @Autowired
  40.     private LocaleMessageUtil localeMessageUtil;
  41.     /**
  42.      * 认证信息(身份验证) Authentication 是用来验证用户身份
  43.      */
  44.     @Override
  45.     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  46.         //1.验证用户名
  47.         User user = null;
  48.         String loginName = (String) token.getPrincipal();
  49.         if (Validator.isEmail(loginName)) {
  50.             user = userService.findByEmail(loginName);
  51.         } else {
  52.             user = userService.findByUserName(loginName);
  53.         }
  54.         if (user == null) {
  55.             //用户不存在
  56.             log.info("第三方登录,用户不存在! 登录名:{}, 密码:{}", loginName,token.getCredentials());
  57.             return null;
  58.         }
  59.         //3.封装authenticationInfo,准备验证密码
  60.         SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
  61.                 user, // 用户名
  62.                 user.getUserPass(), // 密码
  63.                 null,
  64.                 getName() // realm name
  65.         );
  66.         return authenticationInfo;
  67.     }
  68.     @Override
  69.     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  70.         System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");
  71.         SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  72.         User user = (User) principals.getPrimaryPrincipal();
  73.         List<Role> roles = roleService.listRolesByUserId(user.getUserId());
  74.         for (Role role : roles) {
  75.             authorizationInfo.addRole(role.getRole());
  76.             List<Permission> permissions = permissionService.listPermissionsByRoleId(role.getId());
  77.             for (Permission p : permissions) {
  78.                 authorizationInfo.addStringPermission(p.getPermission());
  79.             }
  80.         }
  81.         return authorizationInfo;
  82.     }
  83. }
  2.ShiroConfig 主要关注65-86行
  1. package com.liuyanzhao.sens.config;
  2. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
  3. import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
  4. import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
  5. import org.apache.shiro.mgt.SecurityManager;
  6. import org.apache.shiro.realm.Realm;
  7. import org.apache.shiro.spring.LifecycleBeanPostProcessor;
  8. import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
  9. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  10. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  11. import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
  12. import org.springframework.context.annotation.Bean;
  13. import org.springframework.context.annotation.Configuration;
  14. import org.springframework.context.annotation.DependsOn;
  15. import java.util.ArrayList;
  16. import java.util.LinkedHashMap;
  17. import java.util.List;
  18. import java.util.Map;
  19. /**
  20.  * @author 言曌
  21.  * @date 2018/8/20 上午6:19
  22.  */
  23. @Configuration
  24. public class ShiroConfig {
  25.     @Bean
  26.     public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
  27.         System.out.println("ShiroConfiguration.shirFilter()");
  28.         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  29.         shiroFilterFactoryBean.setSecurityManager(securityManager);
  30.         //拦截器.
  31.         Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
  32.         // 配置不会被拦截的链接 顺序判断
  33.         filterChainDefinitionMap.put("/static/**""anon");
  34.         filterChainDefinitionMap.put("/upload/**""anon");
  35.         filterChainDefinitionMap.put("/favicon.ico""anon");
  36.         filterChainDefinitionMap.put("/favicon.ico""anon");
  37.         filterChainDefinitionMap.put("/admin/login""anon");
  38.         filterChainDefinitionMap.put("/admin/getLogin""anon");
  39.         //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
  40.         filterChainDefinitionMap.put("/logout""logout");
  41.         //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
  42.         //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
  43.         filterChainDefinitionMap.put("/admin/**""authc");
  44.         filterChainDefinitionMap.put("/backup/**""authc");
  45.         filterChainDefinitionMap.put("/**""anon");
  46.         shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  47.         // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面
  48.         shiroFilterFactoryBean.setLoginUrl("/admin/login");
  49.         // 登录成功后要跳转的链接
  50.         shiroFilterFactoryBean.setSuccessUrl("/");
  51.         //未授权界面;
  52.         shiroFilterFactoryBean.setUnauthorizedUrl("/403");
  53.         return shiroFilterFactoryBean;
  54.     }
  55.     @Bean
  56.     public SecurityManager securityManager() {
  57.         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  58.         securityManager.setAuthenticator(modularRealmAuthenticator());
  59.         List<Realm> realms = new ArrayList<>();
  60.         //密码登录realm
  61.         realms.add(normalRealm());
  62.         //免密登录realm
  63.         realms.add(freeRealm());
  64.         securityManager.setRealms(realms);
  65.         return securityManager;
  66.     }
  67.     /**
  68.      * 系统自带的Realm管理,主要针对多realm
  69.      * */
  70.     @Bean
  71.     public ModularRealmAuthenticator modularRealmAuthenticator(){
  72.         //自己重写的ModularRealmAuthenticator
  73.         UserModularRealmAuthenticator modularRealmAuthenticator = new UserModularRealmAuthenticator();
  74.         modularRealmAuthenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
  75.         return modularRealmAuthenticator;
  76.     }
  77.     /**
  78.      * 需要密码登录的realm
  79.      *
  80.      * @return MyShiroRealm
  81.      */
  82.     @Bean
  83.     public NormalRealm normalRealm() {
  84.         NormalRealm normalRealm = new NormalRealm();
  85.         normalRealm.setCredentialsMatcher(hashedCredentialsMatcher());
  86.         return normalRealm;
  87.     }
  88.     /**
  89.      * 免密登录realm
  90.      *
  91.      * @return MyShiroRealm
  92.      */
  93.     @Bean
  94.     public FreeRealm freeRealm() {
  95.         FreeRealm realm = new FreeRealm();
  96.         //不需要加密,直接用数据库密码进行登录
  97.         return realm;
  98.     }
  99.     /**
  100.      * 凭证匹配器
  101.      * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
  102.      *  所以我们需要修改下doGetAuthenticationInfo中的代码;
  103.      * )
  104.      * @return
  105.      */
  106.     @Bean
  107.     public HashedCredentialsMatcher hashedCredentialsMatcher(){
  108.         HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
  109.         hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
  110.         hashedCredentialsMatcher.setHashIterations(10);//散列的次数,md5("")
  111.         return hashedCredentialsMatcher;
  112.     }
  113.     /**
  114.      *  开启shiro aop注解支持.
  115.      *  使用代理方式;所以需要开启代码支持;
  116.      * @param securityManager
  117.      * @return
  118.      */
  119.     /** * Shiro生命周期处理器 * @return */
  120.     @Bean
  121.     public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
  122.         return new LifecycleBeanPostProcessor();
  123.     }
  124.     @Bean
  125.     @DependsOn({"lifecycleBeanPostProcessor"})
  126.     public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
  127.         DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
  128.         advisorAutoProxyCreator.setProxyTargetClass(true);
  129.         return advisorAutoProxyCreator;
  130.     }
  131.     @Bean
  132.     public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
  133.         AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
  134.         authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
  135.         return authorizationAttributeSourceAdvisor;
  136.     }
  137. }
多 Realm 模式需要重写 ModularRealmAuthenticator   3.重写ModularRealmAuthenticator UserModularRealmAuthenticator.java
  1. package com.liuyanzhao.sens.config;
  2. import com.liuyanzhao.sens.model.dto.UserToken;
  3. import org.apache.shiro.authc.AuthenticationException;
  4. import org.apache.shiro.authc.AuthenticationInfo;
  5. import org.apache.shiro.authc.AuthenticationToken;
  6. import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
  7. import org.apache.shiro.realm.Realm;
  8. import java.util.ArrayList;
  9. import java.util.Collection;
  10. import java.util.List;
  11. /**
  12.  * @author 言曌
  13.  * @date 2019/1/24 下午4:19
  14.  */
  15. public class UserModularRealmAuthenticator extends ModularRealmAuthenticator {
  16.     @Override
  17.     protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken)
  18.             throws AuthenticationException {
  19.         System.out.println("UserModularRealmAuthenticator:method doAuthenticate() execute ");
  20.         // 判断getRealms()是否返回为空
  21.         assertRealmsConfigured();
  22.         // 强制转换回自定义的CustomizedToken
  23.         UserToken userToken = (UserToken) authenticationToken;
  24.         // 登录类型
  25.         String loginType = userToken.getLoginType();
  26.         // 所有Realm
  27.         Collection<Realm> realms = getRealms();
  28.         // 登录类型对应的所有Realm
  29.         List<Realm> typeRealms = new ArrayList<>();
  30.         for (Realm realm : realms) {
  31.             if (realm.getName().contains(loginType)) {
  32.                 typeRealms.add(realm);
  33.             }
  34.         }
  35.         // 判断是单Realm还是多Realm
  36.         if (typeRealms.size() == 1){
  37.             System.out.println("doSingleRealmAuthentication() execute ");
  38.             return doSingleRealmAuthentication(typeRealms.get(0), userToken);
  39.         }
  40.         else{
  41.             System.out.println("doMultiRealmAuthentication() execute ");
  42.             return doMultiRealmAuthentication(typeRealms, userToken);
  43.         }
  44.     }
  45. }
  4.枚举类 LoginType LoginType.java
  1. package com.liuyanzhao.sens.model.enums;
  2. /**
  3.  * @author 言曌
  4.  * @date 2019/1/24 下午5:08
  5.  */
  6. public enum LoginType {
  7.     /**
  8.      * 密码登录
  9.      */
  10.     NORMAL("Normal"),
  11.     /**
  12.      * 免密码登录
  13.      */
  14.     FREE("Free");
  15.     private String desc;
  16.     LoginType(String desc) {
  17.         this.desc = desc;
  18.     }
  19.     public String getDesc() {
  20.         return desc;
  21.     }
  22. }
  5.自定义UsernamePasswordToken UserToken.java
  1. package com.liuyanzhao.sens.model.dto;
  2. import lombok.Data;
  3. import org.apache.shiro.authc.UsernamePasswordToken;
  4. /**
  5.  *
  6.  * 自定义UsernamePasswordToken
  7.  * 必须传loginType
  8.  *
  9.  * @author 言曌
  10.  * @date 2019/1/24 下午4:20
  11.  */
  12. @Data
  13. public class UserToken extends UsernamePasswordToken {
  14.     private String loginType;
  15.     public UserToken() {
  16.     }
  17.     public UserToken(final String username, final String password,
  18.                      final String loginType) {
  19.         super(username, password);
  20.         this.loginType = loginType;
  21.     }
  22. }
   

二、登录

1.正常的密码登录
  1. @PostMapping(value = "/getLogin")
  2. @ResponseBody
  3. public JsonResult getLogin(@ModelAttribute("loginName") String loginName, @ModelAttribute("loginPwd") String loginPwd) {
  4.         Subject subject = SecurityUtils.getSubject();
  5.         UserToken token = new UserToken(loginName, loginPwd, LoginType.FREE.getDesc());
  6.         try {
  7.             subject.login(token);
  8.             if (subject.isAuthenticated()) {
  9.                 //登录成功,修改登录错误次数为0
  10.                 User user = (User) subject.getPrincipal();
  11.                 userService.updateUserLoginNormal(user);
  12.                 return new JsonResult(ResultCodeEnum.SUCCESS.getCode(),"登录成功");
  13.             }
  14.         } catch (UnknownAccountException e) {
  15.             ...
  16.         }
  17.        ...
  18.     }
  2.第三方登录,授权成功后,免密登录
  1. package com.liuyanzhao.sens.web.controller.front;
  2. import cn.hutool.core.date.DateUtil;
  3. import cn.hutool.extra.servlet.ServletUtil;
  4. import com.liuyanzhao.sens.entity.Log;
  5. import com.liuyanzhao.sens.entity.ThirdAppBind;
  6. import com.liuyanzhao.sens.entity.User;
  7. import com.liuyanzhao.sens.model.dto.LogsRecord;
  8. import com.liuyanzhao.sens.model.dto.UserToken;
  9. import com.liuyanzhao.sens.model.enums.BindTypeEnum;
  10. import com.liuyanzhao.sens.model.enums.LoginType;
  11. import com.liuyanzhao.sens.service.*;
  12. import com.liuyanzhao.sens.utils.Response;
  13. import lombok.extern.slf4j.Slf4j;
  14. import org.apache.shiro.SecurityUtils;
  15. import org.apache.shiro.subject.Subject;
  16. import org.springframework.beans.factory.annotation.Autowired;
  17. import org.springframework.stereotype.Controller;
  18. import org.springframework.web.bind.annotation.GetMapping;
  19. import org.springframework.web.bind.annotation.RequestParam;
  20. import javax.servlet.http.HttpServletRequest;
  21. /**
  22.  * @author 言曌
  23.  * @date 2018/5/9 下午2:59
  24.  */
  25. @Controller
  26. @Slf4j
  27. public class AuthController {
  28.     @Autowired
  29.     private QQAuthService qqAuthService;
  30.     @Autowired
  31.     private UserService userService;
  32.     @Autowired
  33.     private ThirdAppBindService thirdAppBindService;
  34.     @Autowired
  35.     private LogService logService;
  36.     /**
  37.      * 第三方授权后会回调此方法,并将code传过来
  38.      *
  39.      * @param code code
  40.      * @return
  41.      */
  42.     @GetMapping("/oauth/qq/callback")
  43.     public String oauthByQQ(@RequestParam(value = "code") String code, HttpServletRequest request) {
  44.         Response<String> tokenResponse = qqAuthService.getAccessToken(code);
  45.         if (tokenResponse.isSuccess()) {
  46.             Response<String> openidResponse = qqAuthService.getOpenId(tokenResponse.getData());
  47.             if (openidResponse.isSuccess()) {
  48.                 //根据openId去找关联的用户
  49.                 ThirdAppBind bind = thirdAppBindService.findByAppTypeAndOpenId(BindTypeEnum.QQ.getValue(), openidResponse.getData());
  50.                 if (bind != null && bind.getUserId() != null) {
  51.                     //执行Login操作
  52.                     User user = userService.findByUserId(bind.getUserId());
  53.                     if (user != null) {
  54.                         Subject subject = SecurityUtils.getSubject();
  55.                         UserToken userToken = new UserToken(user.getUserName(), user.getUserPass(), LoginType.FREE.getDesc());  
  56.                         try {
  57.                             subject.login(userToken);
  58.                         } catch (Exception e) {
  59.                             e.printStackTrace();
  60.                             log.error("第三方登录(QQ)免密码登录失败, cause:{}", e);
  61.                             return "redirect:/admin/login";
  62.                         }
  63.                         logService.saveByLog(new Log(LogsRecord.LOGIN, LogsRecord.LOGIN_SUCCESS + "(QQ登录)", ServletUtil.getClientIP(request), DateUtil.date()));
  64.                         log.info("用户[{}]登录成功(QQ登录)。", user.getUserDisplayName());
  65.                         return "redirect:/admin";
  66.                     }
  67.                 }
  68.             }
  69.         }
  70.         return "redirect:/admin/login";
  71.     }
  72. }
主要关注61-71行  
  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
avatar

发表评论

avatar 登录者:匿名
匿名评论,评论回复后会有邮件通知

  

已通过评论:2   待审核评论数:0
  1. avatar yukiloh

    问题我自己解决了 你的UserModularRealmAuthenticatorif (realm.getName().contains(loginType)) { 这句代码会出现bug,此时获取的realm.getName有大小写 2个解决方案 1. if (realm.getName().toLowerCase().contains(loginType)) { 转为小写,不然即是永远找不到对应的realm! 2.强制命名realm的name 在shiro的config配置类中 @Bean public DefaultUserRealm getDefaultUserRealm() { DefaultUserRealm defaultUserRealm = new DefaultUserRealm(); defaultUserRealm.setName(LoginType.DEFAULT.getDesc()); //此处设定shiro的Name! return defaultUserRealm; } 希望通过审查,给更多人看到

  2. avatar yukiloh

    这对我有用,这个问题几乎困扰了我1天 但是有一个问题 你的案例中重写的ModularRealmAuthenticator中, 对于realm的判断是根据传入的 new UserToken(loginCode, password, LoginType.FREE.getDesc()); 中的LoginType.FREE.getDesc()来决定的吗? 我的案例中虽然没有采用你的realm名称, 但在类似的登录情景中,在修改了LoginType后实行subject.login()登陆时 new UserToken(loginCode, password, LoginType.NORMAL.getDesc()); 和 new UserToken(loginCode, password, LoginType.FREE.getDesc()); 依然还是遍历在查找realm,而不是去指定的realm中进行登录匹配 最后导致错误的账号和密码会返回 AuthenticationException: Authentication token of type [class xyz.murasakichigo.demo.shiro.UserToken] could not be authenticated by any configured realms. Please ensure that at least one realm can authenticate these tokens. 无法抓取UnknownAccountException和IncorrectCredentialsException这两个异常 虽然说问题并不大...但是比较好奇。 总结一下,怎么指定subject.login(token)时去指定的realm进行登录匹配,而不是挨个realm遍历 最后,正常密码登录的示例中 UserToken token = new UserToken(loginName, loginPwd, LoginType.FREE.getDesc()); 此处的枚举应该是NORMAL吧?