开发喵星球

若依实现用户免密登录配置(367)

免密登录常用于短信验证码或第三方应用的无缝登录体验。以下将介绍一种简单而有效的实现方式,当然,您也可以探索其他更多的方法。

1. 创建登录类型的枚举类

package com.ruoyi.framework.shiro.token;

/**
 * 定义登录方式的枚举类型
 */
public enum LoginType
{
    /**
     * 密码登录方式
     */
    PASSWORD("password"),

    /**
     * 免密码登录方式
     */
    NOPASSWD("nopasswd");

    private String description;

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

    public String getDescription()
    {
        return description;
    }
}

2. 自定义用户登录令牌

package com.ruoyi.framework.shiro.token;

import org.apache.shiro.authc.UsernamePasswordToken;

/**
 * 自定义用户登录令牌
 */
public class UserToken extends UsernamePasswordToken
{
    private static final long serialVersionUID = 1L;

    private LoginType loginType;

    public UserToken() {}

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

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

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

    public LoginType getLoginType()
    {
        return loginType;
    }

    public void setLoginType(LoginType loginType)
    {
        this.loginType = loginType;
    }
}

3. 在Realm中实现登录类型的判断

/**
 * 登录认证方法
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException
{
    UserToken userToken = (UserToken) token;
    LoginType loginType = userToken.getLoginType();
    String username = userToken.getUsername();
    String password = userToken.getPassword() != null ? new String(userToken.getPassword()) : "";

    User user;
    try
    {
        if (LoginType.PASSWORD.equals(loginType))
        {
            user = loginService.login(username, password);
        }
        else if (LoginType.NOPASSWD.equals(loginType))
        {
            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 | RoleBlockedException e)
    {
        throw new LockedAccountException(e.getMessage(), e);
    }
    catch (Exception e)
    {
        log.info("用户[{}]登录验证失败: {}", username, e.getMessage());
        throw new AuthenticationException(e.getMessage(), e);
    }

    return new SimpleAuthenticationInfo(user, password, getName());
}

4. 在LoginService中添加免密登录方法

/**
 * 免密码登录方法
 */
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. 调用免密登录方法

UserToken token = new UserToken(username, LoginType.NOPASSWD);
Subject subject = SecurityUtils.getSubject();
subject.login(token);

通过以上步骤,您可以实现用户的免密登录配置,提升用户体验,同时也为系统提供了灵活的认证方式。

   
分类:Java/OOP 作者:无限繁荣, 吴蓉 发表于:2024-10-21 11:05:09 阅读量:79
<<   >>


powered by kaifamiao