当用到三方登录时,例如微信登录等,没法验证密码,又找不到若依密码的解密方式,套用此方法,跳过密码验证,并且为可选的,想让哪个方法登录时要密码或者不要,写上即可。
我使用的是若依不分离版,但参考自官方文档,大差不差,具体见个人情况。
参考地址:若依官方文档
但貌似直接复制的不太行,改动了一下。
首先:
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不需要) (此处改动了,大佬说的没太明白,一开始直接复制的不行)
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);