/** * Copyright (c) 2018 人人开源 All rights reserved. * * https://www.renren.io * * 版权所有,侵权必究! */ package com.epmet.service.impl; import io.jsonwebtoken.Claims; import com.epmet.commons.tools.constant.Constant; import com.epmet.commons.tools.enums.SuperAdminEnum; import com.epmet.commons.tools.exception.ErrorCode; import com.epmet.commons.tools.exception.RenException; import com.epmet.commons.tools.redis.UserDetailRedis; import com.epmet.commons.tools.security.bo.ResourceBO; import com.epmet.commons.tools.security.enums.ResourceAuthEnum; import com.epmet.commons.tools.security.enums.UserKillEnum; import com.epmet.commons.tools.security.user.UserDetail; import com.epmet.commons.tools.utils.Result; import com.epmet.feign.ResourceFeignClient; import com.epmet.feign.UserFeignClient; import com.epmet.jwt.JwtUtils; import com.epmet.service.ResourceService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.AntPathMatcher; import java.util.List; /** * 资源服务 * * @author Mark sunlightcs@gmail.com * @since 1.0.0 */ @Service public class ResourceServiceImpl implements ResourceService { private final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Autowired private UserFeignClient userFeignClient; @Autowired private ResourceFeignClient resourceFeignClient; @Autowired private UserDetailRedis userDetailRedis; @Autowired private JwtUtils jwtUtils; @Override public UserDetail resource(String token, String url, String method) { //1、获取所有资源列表 List resourceList = resourceFeignClient.list(); //2、判断是否在资源列表里 ResourceBO resource = pathMatcher(url, method, resourceList); //3、无需登录认证 if(resource != null && resource.getAuthLevel() == ResourceAuthEnum.NO_AUTH.value()){ return null; } //4、获取用户信息 UserDetail userDetail = getUserDetail(token); //5、登录认证 if(resource != null && resource.getAuthLevel() == ResourceAuthEnum.LOGIN_AUTH.value()){ return userDetail; } //6、不在资源列表里,只要登录了,就有权限访问 if(resource == null){ return userDetail; } //7、当前登录用户是超级管理员 if(userDetail.getSuperAdmin() == SuperAdminEnum.YES.value()){ return userDetail; } //8、需要鉴权,获取用户资源列表 List userResourceList = userDetail.getResourceList(); //9、如果不在用户资源列表里,则无权访问 resource = pathMatcher(url, method, userResourceList); if(resource != null){ return userDetail; } throw new RenException(ErrorCode.FORBIDDEN); } /** * 根据token,获取用户信息 * @param token 用户token * @return 返回用户信息 */ private UserDetail getUserDetail(String token) { //token为空 if(StringUtils.isBlank(token)){ throw new RenException(ErrorCode.NOT_NULL, Constant.TOKEN_HEADER); } //是否过期 Claims claims = jwtUtils.getClaimByToken(token); if(claims == null || jwtUtils.isTokenExpired(claims.getExpiration())){ throw new RenException(ErrorCode.UNAUTHORIZED); } //获取用户ID Long userId = Long.parseLong(claims.getSubject()); //查询Redis,如果没数据,则保持用户信息到Redis UserDetail userDetail = userDetailRedis.get(userId); if(userDetail == null){ //获取用户信息 Result result = userFeignClient.getById(userId); userDetail = result.getData(); if(userDetail == null){ throw new RenException(ErrorCode.ACCOUNT_NOT_EXIST); } //过期时间 long expire = (claims.getExpiration().getTime() - System.currentTimeMillis())/1000; userDetailRedis.set(userDetail, expire); } //Redis有数据,则判断是否被踢出,如果被踢出,则提示重新登录 if(userDetail.getKill() == UserKillEnum.YES.value()){ throw new RenException(ErrorCode.UNAUTHORIZED); } return userDetail; } private ResourceBO pathMatcher(String url, String method, List resourceList){ for (ResourceBO resource : resourceList) { if (StringUtils.isNotBlank(resource.getResourceUrl()) && antPathMatcher.match(resource.getResourceUrl(), url) && method.equalsIgnoreCase(resource.getResourceMethod())) { return resource; } } return null; } }