天天看点

若依框架密码验证环节修改(三方登录时改为跳过密码验证,但正常登录保留密码验证)

当用到三方登录时,例如微信登录等,没法验证密码,又找不到若依密码的解密方式,套用此方法,跳过密码验证,并且为可选的,想让哪个方法登录时要密码或者不要,写上即可。

我使用的是若依不分离版,但参考自官方文档,大差不差,具体见个人情况。

参考地址:若依官方文档

但貌似直接复制的不太行,改动了一下。

首先:

1、新增一个登录类型枚举类LoginType(此处未改动)

package com.ruoyi.framework.shiro.token;

/**
 * 登录类型枚举类
 * 
 * @author ruoyi
 */
public enum LoginType
{
    /**
     * 密码登录
     */
    PASSWORD("password"),
    /**
     * 免密码登录
     */
    NOPASSWD("nopasswd");

    private String desc;

    LoginType(String desc)
    {
        this.desc = desc;
    }

    public String getDesc()
    {
        return desc;
    }
}
           

2、自定义登录Token(此处未改动)

package com.ruoyi.framework.shiro.token;

import org.apache.shiro.authc.UsernamePasswordToken;

/**
 1. 自定义登录Token
 2. 
 3. @author ruoyi
 */
public class UserToken extends UsernamePasswordToken
{
    private static final long serialVersionUID = 1L;

    private LoginType type;

    public UserToken()
    {
    }

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

    public UserToken(String username, LoginType type)
    {
        super(username, "", false, null);
        this.type = type;
    }

    public UserToken(String username, String password, LoginType type)
    {
        super(username, password, false, null);
        this.type = type;
    }

    public LoginType getType()
    {
        return type;
    }

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

3、LoginService添加login方法,去掉密码验证。(此处未改动,在原文档为第4步)

这里在SysLoginService中原有一个login 方法,不用管,直接加这个就行。

我加的时候验证码校验哪里报错,直接从原有的方法中拿一个过来用就可以了。

/**
 * 登录
 */
public User login(String username)
{
	// 验证码校验
	if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA)))
	{
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
		throw new CaptchaException();
	}
	// 用户名或密码为空 错误
	if (StringUtils.isEmpty(username))
	{
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
		throw new UserNotExistsException();
	}

	// 用户名不在指定范围内 错误
	if (username.length() < UserConstants.USERNAME_MIN_LENGTH
			|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
	{
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
		throw new UserPasswordNotMatchException();
	}

	// 查询用户信息
	User user = userService.selectUserByLoginName(username);

	if (user == null)
	{
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists")));
		throw new UserNotExistsException();
	}
	
	if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
	{
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.delete")));
		throw new UserDeleteException();
	}
	
	if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
	{
		AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRemark())));
		throw new UserBlockedException();
	}

	AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
	recordLoginInfo(user);
	return user;
}
           

4、对应Realm中添加登录类型判断,例如UserRealm(这里演示公用一个realm,如单独有免密realm不需要) (此处改动了,大佬说的没太明白,一开始直接复制的不行)

  1. 首先找到framework包下的UserRealm类,然后寻找doGetAuthenticationInfo方法。
  2. try代码中,将原有代码直接改为:
try
{
    /**
     * 强制转换token为自定义token类
     */
    UserToken upToken1 = (UserToken) token;
    /**
     * 获取枚举类型
     * 判断是否需要密码
     */
    LoginType type = upToken1.getType();
    /**
     * 当标识为需要密码时
     */
    if (LoginType.PASSWORD.equals(type))
    {
        //用户名密码正常登录
        user = loginService.login(username, password);
    }
    /**
     * 当标识为不需要密码时
     */
    else if (LoginType.NOPASSWD.equals(type))
    {
        //用户名通过即可
        user = loginService.login(username);
    }
}
           

5.登录方法中加入定义(需要密码或不需要密码)

首先,修改原登录方法,将原先的

UsernamePasswordToken token = new UsernamePasswordToken(username, password, false);
Subject subject = SecurityUtils.getSubject();
           

替换为

/**
 * 配置自定义token类,为需要登录密码
 */
UserToken token = new UserToken(username,password,LoginType.PASSWORD);
Subject subject = SecurityUtils.getSubject();
           

即可。

若在不需要密码登录的方法中,token类如下配置即可:

/**
 * 配置自定义token类,为不需要登录密码
 */
UserToken token = new UserToken(username, LoginType.NOPASSWD);
           

测试,完活

若依框架密码验证环节修改(三方登录时改为跳过密码验证,但正常登录保留密码验证)