Shiro实现免密登陆

一、前言

需求:对接第三方登陆,实现绕过原有Shiro认证登陆。
网上例子都有,基本都可以用,反正我也抄别人的。

二、实现方案

1. 实现UsernamePasswordToken

/**
 * @author jihongyuan
 * @date 2020/1/8 14:42
 * 自定义token 继承UsernamePasswordToken,
 * 账号密码登陆(password) 和 免密登陆(nopassword)
 */

public class EasyUsernameToken extends UsernamePasswordToken {
    private static final long serialVersionUID = -2564928913725078138L;

    private LoginType type;

    public EasyUsernameToken() {
        super();
    }

    /**
     * 免密登录
     */
    public EasyUsernameToken(String username) {
        super(username, "", false, null);
        this.type = LoginType.NOPASSWD;
    }

    /**
     * 账号密码登录
     */
    public EasyUsernameToken(String username, String password, boolean rememberMe) {
        super(username, password, rememberMe, null);
        this.type = LoginType.PASSWORD;
    }

    public LoginType getType() {
        return type;
    }

    public void setType(LoginType type) {
        this.type = type;
    }

}

代码都很简单,没什么要说的

2. LoginType枚举

public enum  LoginType {
    /** 密码登录 */
    PASSWORD("password"),
    /** 密码登录 */
    NOPASSWD("nopassword");
    /** 状态值 */
    private String code;
    private LoginType(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }
}

3. 实现HashedCredentialsMatcher

public class EasyCredentialsMatch extends HashedCredentialsMatcher {

    /**
     * 重写方法
     * 区分 密码和非密码登录
     * 此次无需记录登录次数 详情看SysPasswordService
     */
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        EasyUsernameToken easyUsernameToken = (EasyUsernameToken) token;

        //免密登录,不验证密码
        if (LoginType.NOPASSWD.equals(easyUsernameToken.getType())) {
            return true;
        }

        //密码登录
        Object tokenHashedCredentials = hashProvidedCredentials(token, info);
        Object accountCredentials = getCredentials(info);
        return equals(tokenHashedCredentials, accountCredentials);
    }
}

代码都很简单,没啥要注意的。

4. Spring Boot配置

    @Bean
    public EasyCredentialsMatch customCredentialsMatch() {
        EasyCredentialsMatch customCredentialsMatch = new EasyCredentialsMatch();
        customCredentialsMatch.setHashAlgorithmName("md5");
        customCredentialsMatch.setHashIterations(3);
        customCredentialsMatch.setStoredCredentialsHexEncoded(true);
        return customCredentialsMatch;
    }

5. 实现AuthorizingRealm

public class UserRealm extends AuthorizingRealm {
  @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
      ......................
    }

      /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        EasyUsernameToken upToken = (EasyUsernameToken) token;
        String username = upToken.getUsername();

        SysUser user = null;
        // 密码登录
        if (upToken.getType().getCode().equals(LoginType.PASSWORD.getCode())) {
            String password;
            if (upToken.getPassword() != null) {
                password = new String(upToken.getPassword());
                try {
                    user = loginService.login(username, password);
                } ......
                catch (Exception e) {
                    log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
                    throw new AuthenticationException(e.getMessage(), e);
                }
            }
        } else if (upToken.getType().getCode().equals(LoginType.NOPASSWD.getCode())) {
            // 第三方登录
            ......
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, upToken.getPassword(), getName());
        return info;
    }
}

6. 使用

    private AjaxResult login(String username, String password, Boolean rememberMe) {
        EasyUsernameToken token = new EasyUsernameToken(username, password, rememberMe);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            return success();
        } catch (AuthenticationException e) {
            String msg = "用户或密码错误";
            if (StringUtils.isNotEmpty(e.getMessage())) {
                msg = e.getMessage();
            }
            return error(msg);
        }
    }

三、总结

代码都网上抄的,找不到原文了。
注意一下强转EasyUsernameToken就好。

代码非常的简单!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容