Cloud-Platform 学习——Part4 查看在线用户、强制退出用户

用户登录

校验token,并解析token获取用户信息,并把用户信息存入redis中,分别存入两种形式;
一种是以key-value字符串形式存入redis,一种是以有序集合zset形式存入redis;
前一种便于查看当前用户是否已登录,后一种便于管理人员查看当前在线用户并执行相关操作

 @Override
    public Map login(JwtAuthenticationRequest authenticationRequest) throws Exception {
		//校验用户信息
        UserInfo info = permissionService.validate(authenticationRequest.getUsername(), authenticationRequest.getPassword());
        if (!StringUtils.isEmpty(info.getId())) {
            JWTInfo jwtInfo = new JWTInfo(info.getUsername(), info.getId() + "", info.getName());
			//生成token
            String token = jwtTokenUtil.generateToken(jwtInfo);
            Map<String, String> result = new HashMap<>();
            result.put("accessToken", token);
            result.put("id", info.id);
            //创建会话
            writeOnlineLog(jwtInfo);
            return result;
        }
        throw new UserInvalidException("用户不存在或账户密码错误!");
    }
/**
     * 创建当前会话
     * @param jwtInfo
     */
    @Async
    public void  writeOnlineLog(JWTInfo jwtInfo) {
        final UserAgent userAgent = UserAgent.parseUserAgentString(WebUtils.getRequest().getHeader("User-Agent"));
        final String ip = IpUtils.getRemoteIP(WebUtils.getRequest());
        String address = AddressUtils.getRealAddressByIP(ip);
        OnlineLog onlineLog = new OnlineLog();
        String os = userAgent.getOperatingSystem().getName();// 获取客户端操作系统   
        String browser = userAgent.getBrowser().getName();// 获取客户端浏览器
        onlineLog.setBrowser(browser);
        onlineLog.setIpaddr(ip);
        onlineLog.setTokenId(jwtInfo.getTokenId());
        onlineLog.setLoginTime(System.currentTimeMillis());
        onlineLog.setUserId(jwtInfo.getId());
        onlineLog.setUserName(jwtInfo.getName());
        onlineLog.setLoginLocation(address);
        onlineLog.setOs(os);
        //当前用户token存入redis
        stringRedisTemplate.opsForValue().set(RedisKeyConstant.REDIS_KEY_TOKEN + ":" + jwtInfo.getTokenId(), JSON.toJSONString(onlineLog, false), expire, TimeUnit.MINUTES);
        //当前用户token存入zset有序集合,关联分数
        stringRedisTemplate.opsForZSet().add((RedisKeyConstant.REDIS_KEY_TOKEN), jwtInfo.getTokenId(), 0);
    }

zset 不允许重复的成员。zset 的每个元素都会关联一个分数(分数可以重复),redis 通过分数来为集合中的成员进行从小到大的排序

请求过滤器校验

public class AccessGatewayFilter implements GlobalFilter {

    private IJWTInfo getJWTUser(ServerHttpRequest request, ServerHttpRequest.Builder ctx) throws Exception {
		//获取请求中的token信息
        List<String> strings = request.getHeaders().get(userAuthConfig.getTokenHeader()); 
        String authToken = null;
        if (strings != null) {
            authToken = strings.get(0);
        }
        if (StringUtils.isBlank(authToken)) {
            strings = request.getQueryParams().get("token"); //如果 Authorization信息为空,则获取携带参数 token
            if (strings != null) {
                authToken = strings.get(0);
            }
        }
        IJWTInfo infoFromToken = userAuthUtil.getInfoFromToken(authToken);
        //根据token获取用户会话信息
        String s = stringRedisTemplate.opsForValue().get(RedisKeyConstant.REDIS_KEY_TOKEN + ":" + infoFromToken.getTokenId());
        if (StringUtils.isBlank(s)) {
			//无会话表示当前登录已过期 / 已经下线(包括被强制下线)
            throw new UserTokenException("User token expired!");
        }

        ctx.header(userAuthConfig.getTokenHeader(), authToken);
        BaseContextHandler.setToken(authToken);
        return infoFromToken;
    }

查询用户登录状态/强制下线

@RestController
@RequestMapping("online")
public class OnlineController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 查询在线用户列表
     * @param limit 每页条数
     * @param offset 页码
     * @return
     */
    @RequestMapping("/page")
    public TableResultResponse<OnlineLog> getOnlineInfo(@RequestParam(defaultValue = "10") int limit, @RequestParam(defaultValue = "1") int offset) {
        stringRedisTemplate.opsForValue();
        //从redis的zset有序集合中根据分数分页查询用户id列表
        Set<String> ids = stringRedisTemplate.opsForZSet().reverseRange(RedisKeyConstant.REDIS_KEY_TOKEN, (offset - 1) * limit, (offset - 1) * limit + limit - 1);
        List<OnlineLog> logs = new ArrayList<>(ids.size());
        for (String id : ids) {
            String s = stringRedisTemplate.opsForValue().get(RedisKeyConstant.REDIS_KEY_TOKEN + ":" + id);
            if (s == null) {
                stringRedisTemplate.opsForZSet().remove(RedisKeyConstant.REDIS_KEY_TOKEN, id);
            } else {
                logs.add(JSON.parseObject(s, OnlineLog.class));
            }
        }
        return new TableResultResponse<>(stringRedisTemplate.opsForZSet().size(RedisKeyConstant.REDIS_KEY_TOKEN), logs);
    }

    /**
     * 强退用户
     * @param tokenId
     * @return
     */
    @RequestMapping("/{id}")
    public ObjectRestResponse forceLogout(@PathVariable("id") String tokenId) {
		//redis中删除用户会话信息,是用户无法通过请求过滤器校验
        stringRedisTemplate.delete(RedisKeyConstant.REDIS_KEY_TOKEN + ":" + tokenId);
        stringRedisTemplate.opsForZSet().remove(RedisKeyConstant.REDIS_KEY_TOKEN, tokenId);
        return new ObjectRestResponse<>();
    }

}

你可能感兴趣的:(Cloud-Platform,平台源码学习,学习)