基于ruoyi中shiro框架如何实现免密登录
所做项目与第三方合作,系统间存在一些接口调用,需要做授权登录。我们的项目整体使用springboot框架结合部分ruoyi的后台管理框架,认证登陆采用了shiro框架,密码在数据库中经过盐值(salt)+Md5加密,外部无法获知密码明文,导致无法验证通过,所以想到了免密登录的方式解决。
若依框架官网:https://gitee.com/y_project/RuoYi
经过一番摸索,也总算弄出来了,在此记录一下
1,新增一个登录类型枚举类LoginType
package com.ht.framework.shiro.token;
/**
* 登录类型枚举类
*
* @author hcg
*/
public enum LoginType
{
/**
* 密码登录
*/
PASSWORD("password"),
/**
* 免密码登录
*/
NOPASSWD("nopasswd");
private String desc;
LoginType(String desc)
{
this.desc = desc;
}
public String getDesc()
{
return desc;
}
}
2、自定义登录Token,继承UsernamePasswordToken类,通过构造方法区分密码登录和免密登录。
package com.ht.framework.shiro.token;
import org.apache.shiro.authc.UsernamePasswordToken;
/**
* 自定义登录Token
*
* @author huang
*/
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、对应Realm中添加登录类型判断,例如UserRealm
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
UserToken upToken = (UserToken) token;
LoginType type = upToken.getType();
String username = upToken.getUsername();
String password = "";
if (upToken.getPassword() != null)
{
password = new String(upToken.getPassword());
}
User user = null;
try
{
if (LoginType.PASSWORD.equals(type))
{
//需要密码登录
user = loginService.login(username, password);
}
else if (LoginType.NOPASSWD.equals(type))
{
//免密登录
user = loginService.login(username);
}
}
catch (CaptchaException e)
{
throw new AuthenticationException(e.getMessage(), e);
}
catch (UserNotExistsException e)
{
throw new UnknownAccountException(e.getMessage(), e);
}
catch (UserPasswordNotMatchException e)
{
throw new IncorrectCredentialsException(e.getMessage(), e);
}
catch (UserPasswordRetryLimitExceedException e)
{
throw new ExcessiveAttemptsException(e.getMessage(), e);
}
catch (UserBlockedException e)
{
throw new LockedAccountException(e.getMessage(), e);
}
catch (RoleBlockedException e)
{
throw new LockedAccountException(e.getMessage(), e);
}
catch (Exception e)
{
log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage());
throw new AuthenticationException(e.getMessage(), e);
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
}
4,LoginService添加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;
}
5、在对应的登录方法中传入LoginType.NOPASSWD调用
需要密码的登录方式
UserToken token=new UserToken(username,password, LoginType.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);
}
免密登录方式
User user = userMapper.selectUserByLoginName(username);
UserToken token=new UserToken(user.getLoginName(), LoginType.NOPASSWD);
Subject subject = SecurityUtils.getSubject();
subject.login(token);
//重定向首页地址
return "redirect:/newindex";
到此为止,输入正确的地址就可以实现免密登录了!!
特别声明:
此记录是在ruoyi的shiro框架上进行的进一步修改,只做笔记之用。
如无用你可以尝试:
如何实现用户免密登录配置方法
https://blog.csdn.net/xxfamly/article/details/92839999