若依项目如何实现一个账户只能一个人登录(即,限制账户不允许多终端登录)

一、不分离版

在application.yml设置maxSession为1即可。修改shiro的配置

二、分离版springboot+vue

1、application.yml新增一个配置soloLogin用于限制多终端同时登录。修改token的配置。

2、Constants.java新增一个常量LOGIN_USERID_KEY公用。

3、调整TokenService.java,存储&刷新缓存用户编号信息

 4、自定义退出处理类LogoutSuccessHandlerImpl.java清除缓存方法添加用户编号。

5、登录方法SysLoginService.java,验证如果用户不允许多终端同时登录,清除缓存信息。

一、不分离版
在application.yml设置maxSession为1即可。
修改shiro的配置

shiro:
  session:
    # 同一个用户最大会话数,比如2的意思是同一个账号允许最多同时两个人登录(默认-1不限制)
    maxSession: 1
    # 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户
    kickoutAfter: false
二、分离版springboot+vue
1、application.yml新增一个配置soloLogin用于限制多终端同时登录。
修改token的配置。

token:
    # 是否允许账户多终端同时登录(true允许 false不允许)
    soloLogin: false
2、Constants.java新增一个常量LOGIN_USERID_KEY公用。
路径:com.zhdj.common.constant.Constants.java。

/**
 * 登录用户编号 redis key
 */
public static final String LOGIN_USERID_KEY = "login_userid:";
3、调整TokenService.java,存储&刷新缓存用户编号信息
路径:com.zhdj.framework.web.service.TokenService.java

// 是否允许账户多终端同时登录(true允许 false不允许)
@Value("${token.soloLogin}")
private boolean soloLogin;
 
/**
 * 删除用户身份信息
 */
public void delLoginUser(String token, Long userId)
{
    if (StringUtils.isNotEmpty(token))
    {
        String userKey = getTokenKey(token);
        redisCache.deleteObject(userKey);
    }
    //在原有代码上添加下面的代码
    if (!soloLogin && StringUtils.isNotNull(userId))
    {
        String userIdKey = getUserIdKey(userId);
        redisCache.deleteObject(userIdKey);
    }
}
 
/**
 * 刷新令牌有效期
 * 
 * @param loginUser 登录信息
 */
public void refreshToken(LoginUser loginUser)
{
    loginUser.setLoginTime(System.currentTimeMillis());
    loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
    // 根据uuid将loginUser缓存
    String userKey = getTokenKey(loginUser.getToken());
    redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    //在原有代码上添加下面的代码
    if (!soloLogin)
    {
        // 缓存用户唯一标识,防止同一帐号,同时登录
        String userIdKey = getUserIdKey(loginUser.getUser().getUserId());
        redisCache.setCacheObject(userIdKey, userKey, expireTime, TimeUnit.MINUTES);
    }
}
 
//添加下面的代码
private String getUserIdKey(Long userId)
{
    return Constants.LOGIN_USERID_KEY + userId;
}
 4、自定义退出处理类LogoutSuccessHandlerImpl.java清除缓存方法添加用户编号。
路径:com.zhdj.framework.security.handle.LogoutSuccessHandlerImpl.java

// 删除用户缓存记录
// 在原代码参数中添加用户编号:loginUser.getUser().getUserId()
tokenService.delLoginUser(loginUser.getToken(), loginUser.getUser().getUserId());
5、登录方法SysLoginService.java,验证如果用户不允许多终端同时登录,清除缓存信息。
路径:com.zhdj.framework.web.service.SysLoginService.java

// 是否允许账户多终端同时登录(true允许 false不允许)
    @Value("${token.soloLogin}")
    private boolean soloLogin;
 
    /**
     * 登录验证
     * 
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public String login(String username, String password, String code, String uuid)
    {
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        // 验证码开关
        if (captchaEnabled)
        {
            validateCaptcha(username, code, uuid);
        }
        // 用户验证
        Authentication authentication = null;
        try
        {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch (Exception e)
        {
            if (e instanceof BadCredentialsException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        finally
        {
            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        recordLoginInfo(loginUser.getUserId());
        // 添加到这里
        // 判断是否允许账户多终端同时登录
        if (!soloLogin)
        {
            // 如果用户不允许多终端同时登录,清除缓存信息
            String userIdKey = Constants.LOGIN_USERID_KEY + loginUser.getUser().getUserId();
            String userKey = redisCache.getCacheObject(userIdKey);
            if (StringUtils.isNotEmpty(userKey))
            {
                redisCache.deleteObject(userIdKey);
                redisCache.deleteObject(userKey);
            }
        }
        // 生成token
        return tokenService.createToken(loginUser);
    }

你可能感兴趣的:(java,spring,boot,redis)