SSM框架下Shiro免密登录

在做微信授权登陆的时候,由于使用shiro框架进行认证登陆,没有认证授权无法建立会话。
数据库中的密码经过md5加密,通过openid查询出账号密码也无法进行授权登陆,所以需要实现Shiro免密授权登陆功能,以防后续踩坑。

1.整体思路

自定义token,加入免密标识符,在进行授权时判断是密码登陆或无密码登陆,自定义密码认证方法,即写一个方法继承HashedCredentialsMatcher,重写其中的doCredentialsMatch,将其中的token改写为自定义的token,最后将自己写的密码认证方法注入shiro

2.源码分析

在shiro的配置文件中有个配置credentialsMatcher,该方法为重写方法,自定义登陆模式,可设置密码错误锁定功能,我们需要的就是改写这个方法

image.png
1)在ShiroDbRealm中,认证使用的是UserPasswordToken
image.png
其默认使用username,password进行认证
image.png

image.png
网上有方法另写token继承UsernamePasswordToken重写getCredentials方法修改getPassword() 为 return null。此方法过于简单粗暴,顺带连密码认证也给删除了,不建议使用。
2)Shiro的密码认证在org.apache.shiro.authc.credential包下HashedCredentialsMatcher.class方法内
image.png
其中密码认证:doCredentialsMatch方法
image.png

3.免密登陆方法

1)创建一个枚举类(enum )LoginType
public enum LoginType {
    PASSWORD("password"), // 密码登录
    NOPASSWD("nopassword"); // 免密登录

    private String code;// 状态值

    private LoginType(String code) {
    this.code = code;
    }
    public String getCode () {
    return code;
    }
}
2)自定义token 继承UsernamePasswordToken,通过构造方法来区分 账号密码登陆(password) 和 免密登陆(nopassword)
package com.pasic.commons.shiro;

import org.apache.shiro.authc.UsernamePasswordToken;

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

    private LoginType type;


    public EasyTypeToken() {
    super();
    }


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

    public LoginType getType() {
    return type;
    }


    public void setType(LoginType type) {
    this.type = type;
    }
}
3)修改ShiroDbRealm:将UsernamePasswordToen修改为自定义token
image.png
4)找到RetryLimitCredentialsMatcher重写doCredentialsMatch,将token强转为自定义token,如果是免密登陆则直接返回 true
@Override
    public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) {
        EasyTypeToken tk = (EasyTypeToken) authcToken;
        if(tk.getType().equals(LoginType.NOPASSWD)){
                return true;
        }
         
        String username = (String) authcToken.getPrincipal();
        //retry count + 1
        AtomicInteger retryCount = passwordRetryCache.get(username);
        if(retryCount == null) {
            retryCount = new AtomicInteger(0);
            passwordRetryCache.put(username, retryCount);
        }
        if(retryCount.incrementAndGet() > 5) {
            //if retry count > 5 throw
            logger.warn("username: " + username + " tried to login more than 5 times in period");  
            throw new ExcessiveAttemptsException("用户名: " + username + " 密码连续输入错误超过5次,锁定半小时!"); 
        } else {
            passwordRetryCache.put(username, retryCount);
        }

        boolean matches = super.doCredentialsMatch(authcToken, info);
        if(matches) {
            //clear retry data
            passwordRetryCache.remove(username);
        }
        return matches;
    }

就此配置完成

Login调用

1)账号密码登陆
Subject user = SecurityUtils.getSubject();
EasyTypeToken token = new EasyTypeToken(username, password);
user.login(token);
2)免密登陆
Subject user = SecurityUtils.getSubject();
EasyTypeToken token = new EasyTypeToken(username);
user.login(token);

通过不同的构造函数生成不同的LoginType,从而实现账号密码登陆与免密登陆分离,完成。

你可能感兴趣的:(SSM框架下Shiro免密登录)