You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

147 lines
4.9 KiB

/**
* 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<ResourceBO> 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<ResourceBO> 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<UserDetail> 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<ResourceBO> resourceList){
for (ResourceBO resource : resourceList) {
if (StringUtils.isNotBlank(resource.getResourceUrl()) && antPathMatcher.match(resource.getResourceUrl(), url)
&& method.equalsIgnoreCase(resource.getResourceMethod())) {
return resource;
}
}
return null;
}
}