(五)Spring Boot 集成 Shiro 多登陆方式登录

github

历史文章

(一)Spring Boot 集成 Shiro 权限管理与密码加盐

(二)Spring Boot 集成 Shiro 记住我功能

(三)Spring Boot 集成 Shiro 权限缓存功能

(四)Spring Boot 集成 Shiro 用户管理与登录保护

主要完成功能

用户可以使用账号密码登录或者手机验证码登录

shiro 有三种认证策略 AuthenticationStrategy

  • AtLeastOneSuccessfulStrategy 只要有一个成功即成功认证
  • FirstSuccessfulStrategy 第一个认证成功即成功认证
  • AllSuccessfulStrategy 全部认证成功即成功认证否则失败

默认是 AtLeastOneSuccessfulStrategy

修改 MyRealm 为 BaseRealm 并将 doGetAuthenticationInfo 交由子类实现

实现两个 Realm

  • PasswordRealm
  • PhoneCodeRealm
public class PasswordRealm extends BaseRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取用户的输入的账号
        UserToken userToken = (UserToken) authenticationToken;
        if (userToken.getLoginType() == LoginType.PASSWORD) {
            //通过username从数据库中查找 User对象
            User user = userMapper.selectByName(userToken.getUsername());
            if (user == null) {
                //没有返回登录用户名对应的SimpleAuthenticationInfo对象时,就会在LoginController中抛出UnknownAccountException异常
                throw new UnknownAccountException("用户不存在");
            }
            //使用密码加盐的方式验证密码的安全,盐为用户注册时设置的用户名
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user, //用户名
                    user.getPassword(), //密码
                    ByteSource.Util.bytes(user.getSalt()),//salt
                    getName()  //realm name
            );
            return authenticationInfo;
        } else {
            return null;
        }
    }
}
public class PhoneCodeRealm extends BaseRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UserToken userToken = (UserToken) authenticationToken;
        if (userToken.getLoginType() == LoginType.PHONE_CODE) {
            User user = userMapper.selectByName(userToken.getUsername());
            if (user == null) {
                throw new UnknownAccountException("用户不存在");
            }
            SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    user, //用户名
                    "1234", //验证码,该验证码应该从数据库中查找
                    getName()  //realm name
            );
            return authenticationInfo;
        } else {
            return null;
        }
    }
}
public enum LoginType {
    PASSWORD, PHONE_CODE;
}
public class UserToken extends UsernamePasswordToken {
    private LoginType loginType;

    public UserToken(String username, String password, boolean rememberMe, LoginType loginType) {
        super(username, password, rememberMe);
        this.loginType = loginType;
    }

    public LoginType getLoginType() {
        return loginType;
    }

    public void setLoginType(LoginType loginType) {
        this.loginType = loginType;
    }
}

修改 ShiroConfig 配置类

由之前的配置的单个 Realm 改为 Realm List

@Bean
SecurityManager securityManager() {
    DefaultSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
    // >>>>修改为 List
    List realmList = new ArrayList<>();
    realmList.add(passwordRealm());
    realmList.add(phoneRealm());
    defaultSecurityManager.setRealms(realmList);
    // <<<<
    defaultSecurityManager.setRememberMeManager(rememberMeManager());
    defaultSecurityManager.setCacheManager(cacheManager());
    defaultSecurityManager.setSessionManager(sessionManager());
    return defaultSecurityManager;
}

@Bean
BaseRealm passwordRealm() {
    BaseRealm myRealm = new PasswordRealm();
    myRealm.setCredentialsMatcher(hashedCredentialsMatcher()); //设置解密规则
    return myRealm;
}

@Bean
BaseRealm phoneRealm() {
    return new PhoneCodeRealm();//去除解密策略
}

修改登录接口

/**
 * 登录接口
 *
 * @param username
 * @param password
 */
@GetMapping("/doLogin")
public String doLogin(String username, String password, boolean rememberMe) {
    Subject subject = SecurityUtils.getSubject();
    if (!subject.isAuthenticated()) {
        try {
            UserToken token = new UserToken(username, password, rememberMe, LoginType.PASSWORD);
            subject.login(token);
            return "登录成功";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "登录失败";
        }
    } else {
        return "已经登录成功";
    }
}

/**
 * 登录接口 使用 code 替换 password,并去掉加解密
 *
 * @param username
 * @param code
 */
@GetMapping("/doLoginByCode")
public String doLoginByCode(String username, String code, boolean rememberMe) {
    Subject subject = SecurityUtils.getSubject();
    if (!subject.isAuthenticated()) {
        try {
            UserToken token = new UserToken(username, code, rememberMe, LoginType.PHONE_CODE);
            subject.login(token);
            return "登录成功";
        } catch (AuthenticationException e) {
            e.printStackTrace();
            return "登录失败";
        }
    } else {
        return "已经登录成功";
    }
}

测试

使用账号密码登录,之后退出

使用账号验证码登录,之后退出

有用的话关注我的微信公众号吧!

你可能感兴趣的:((五)Spring Boot 集成 Shiro 多登陆方式登录)