mirror of https://github.com/elunez/eladmin
优化SecurityUtils的方法,减少与redis之间的交互,提高性能
parent
255a3254ce
commit
1c4741e3eb
|
@ -16,11 +16,10 @@
|
|||
package me.zhengjie.config;
|
||||
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
|
@ -30,7 +29,7 @@ public class ElPermissionConfig {
|
|||
|
||||
public Boolean check(String ...permissions){
|
||||
// 获取当前用户的所有权限
|
||||
List<String> elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
|
||||
Set<String> elPermissions = SecurityUtils.listPermission();
|
||||
// 判断当前用户的所有权限是否包含接口上定义的权限
|
||||
return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package me.zhengjie.constant;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 安全定义
|
||||
* </p>
|
||||
*
|
||||
* @author miaoyj
|
||||
* @version 1.0.0-SNAPSHOT
|
||||
* @since 2020-08-12
|
||||
*/
|
||||
public interface SecurityConstant {
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
String JWT_KEY_USER_ID = "userid";
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
String JWT_KEY_USERNAME = "username";
|
||||
|
||||
/**
|
||||
* 用户权限
|
||||
*/
|
||||
String JWT_KEY_PERMISSION = "permissions";
|
||||
/**
|
||||
* 用户数据范围-部门ids
|
||||
*/
|
||||
String JWT_KEY_DATA_SCOPE_DEPT_IDS = "data_scope_dept_ids";
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import me.zhengjie.constant.SecurityConstant;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* http
|
||||
* </p>
|
||||
*
|
||||
* @author miaoyj
|
||||
* @since 2022-07-05
|
||||
*/
|
||||
public class HttpUtil {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 设置header的用户信息
|
||||
* </p>
|
||||
*
|
||||
* @param userDetails /
|
||||
* @return /
|
||||
*/
|
||||
public static Map<String, Object> getUserHeaders(UserDetails userDetails) {
|
||||
Map<String, Object> httpHeaders = new HashMap<>();
|
||||
if (userDetails != null) {
|
||||
//用户基本信息
|
||||
String userId = new JSONObject(new JSONObject(userDetails).get("user")).get("id", String.class);
|
||||
String username = userDetails.getUsername();
|
||||
List<String> elPermissions = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
|
||||
//部门id
|
||||
JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes"));
|
||||
List<Long> dataScopeDeptIds = JSONUtil.toList(array,Long.class);
|
||||
List<String> dataScopeDeptIdsList = new ArrayList<>();
|
||||
if (CollUtil.isNotEmpty(dataScopeDeptIds)) {
|
||||
dataScopeDeptIdsList = dataScopeDeptIds.stream().map(o -> String.valueOf(o)).collect(Collectors.toList());
|
||||
}
|
||||
httpHeaders.put(SecurityConstant.JWT_KEY_USER_ID, userId);
|
||||
httpHeaders.put(SecurityConstant.JWT_KEY_USERNAME, username);
|
||||
httpHeaders.put(SecurityConstant.JWT_KEY_PERMISSION, elPermissions);
|
||||
httpHeaders.put(SecurityConstant.JWT_KEY_DATA_SCOPE_DEPT_IDS, dataScopeDeptIdsList);
|
||||
}
|
||||
return httpHeaders;
|
||||
}
|
||||
}
|
|
@ -15,10 +15,14 @@
|
|||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 获取 HttpServletRequest
|
||||
|
@ -30,4 +34,42 @@ public class RequestHolder {
|
|||
public static HttpServletRequest getHttpServletRequest() {
|
||||
return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取头部信息
|
||||
* </p>
|
||||
*
|
||||
* @param headerName 头部名称
|
||||
* @return /
|
||||
*/
|
||||
public static String getHeader(String headerName) {
|
||||
return getHttpServletRequest().getHeader(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取头部信息
|
||||
* </p>
|
||||
*
|
||||
* @param headerName 头部名称
|
||||
* @return /
|
||||
*/
|
||||
public static Long getHeaderLong(String headerName) {
|
||||
return Convert.toLong(getHeader(headerName));
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取头部集合
|
||||
* </p>
|
||||
*
|
||||
* @param headerName 头部名称
|
||||
* @return /
|
||||
*/
|
||||
public static Set<String> getHeaders(String headerName) {
|
||||
Enumeration<String> values = getHttpServletRequest().getHeaders(headerName);
|
||||
return CollUtil.newHashSet(true, values);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
package me.zhengjie.utils;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.constant.SecurityConstant;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.utils.enums.DataScopeEnum;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
@ -26,10 +26,15 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 获取当前登录的用户
|
||||
*
|
||||
* @author Zheng Jie
|
||||
* @date 2019-01-17
|
||||
*/
|
||||
|
@ -38,11 +43,14 @@ public class SecurityUtils {
|
|||
|
||||
/**
|
||||
* 获取当前登录的用户
|
||||
*
|
||||
* @return UserDetails
|
||||
*/
|
||||
public static UserDetails getCurrentUser() {
|
||||
UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class);
|
||||
return userDetailsService.loadUserByUsername(getCurrentUsername());
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
return userDetailsService.loadUserByUsername(userDetails.getUsername());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,45 +59,85 @@ public class SecurityUtils {
|
|||
* @return 系统用户名称
|
||||
*/
|
||||
public static String getCurrentUsername() {
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null) {
|
||||
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");
|
||||
return getHeaderByAuthException(SecurityConstant.JWT_KEY_USERNAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户ID
|
||||
*
|
||||
* @return 系统用户ID
|
||||
*/
|
||||
public static Long getCurrentUserId() {
|
||||
return getLongHeaderByAuthException(SecurityConstant.JWT_KEY_USER_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的数据权限
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public static List<Long> getCurrentUserDataScope() {
|
||||
Set<String> deptStrIds = RequestHolder.getHeaders(SecurityConstant.JWT_KEY_DATA_SCOPE_DEPT_IDS);
|
||||
List<Long> deptIds = new ArrayList<>();
|
||||
if (CollUtil.isNotEmpty(deptStrIds)) {
|
||||
deptIds = deptStrIds.stream().map(o -> Long.parseLong(o)).collect(Collectors.toList());
|
||||
}
|
||||
if (authentication.getPrincipal() instanceof UserDetails) {
|
||||
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
|
||||
return userDetails.getUsername();
|
||||
return deptIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据权限级别
|
||||
*
|
||||
* @return 级别
|
||||
*/
|
||||
public static String getDataScopeType() {
|
||||
List<Long> dataScopes = getCurrentUserDataScope();
|
||||
if (dataScopes.size() != 0) {
|
||||
return "";
|
||||
}
|
||||
return DataScopeEnum.ALL.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取权限列表
|
||||
* </p>
|
||||
*
|
||||
* @return /
|
||||
*/
|
||||
public static Set<String> listPermission() {
|
||||
return RequestHolder.getHeaders(SecurityConstant.JWT_KEY_PERMISSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 获取header,验证用户信息抛出异常
|
||||
* </p>
|
||||
*
|
||||
* @author miaoyj
|
||||
* @since 2022-06-23
|
||||
*/
|
||||
private static String getHeaderByAuthException(String headerName) {
|
||||
String value = RequestHolder.getHeader(headerName);
|
||||
if (StrUtil.isNotBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统用户ID
|
||||
* @return 系统用户ID
|
||||
* <p>
|
||||
* 获取header,验证用户信息抛出异常
|
||||
* </p>
|
||||
*
|
||||
* @author miaoyj
|
||||
* @since 2022-06-23
|
||||
*/
|
||||
public static Long getCurrentUserId() {
|
||||
UserDetails userDetails = getCurrentUser();
|
||||
return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户的数据权限
|
||||
* @return /
|
||||
*/
|
||||
public static List<Long> getCurrentUserDataScope(){
|
||||
UserDetails userDetails = getCurrentUser();
|
||||
JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes"));
|
||||
return JSONUtil.toList(array,Long.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据权限级别
|
||||
* @return 级别
|
||||
*/
|
||||
public static String getDataScopeType() {
|
||||
List<Long> dataScopes = getCurrentUserDataScope();
|
||||
if(dataScopes.size() != 0){
|
||||
return "";
|
||||
private static Long getLongHeaderByAuthException(String headerName) {
|
||||
Long value = RequestHolder.getHeaderLong(headerName);
|
||||
if (value != null && value > 0) {
|
||||
return value;
|
||||
}
|
||||
return DataScopeEnum.ALL.getValue();
|
||||
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package me.zhengjie.wrapper;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* request修改header包装
|
||||
* </p>
|
||||
*
|
||||
* @author miaoyj
|
||||
* @since 2022-06-21
|
||||
*/
|
||||
public class HeaderMapRequestWrapper extends HttpServletRequestWrapper {
|
||||
private Map headerMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* construct a wrapper for this request
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
public HeaderMapRequestWrapper(HttpServletRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* add a header with given name and value
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
public void addHeader(String name, String value) {
|
||||
headerMap.put(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 批量添加
|
||||
* </p>
|
||||
*
|
||||
* @param headers /
|
||||
*/
|
||||
public void addHeaders(Map headers) {
|
||||
headerMap.putAll(headers);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
String headerValue = super.getHeader(name);
|
||||
if (headerMap.containsKey(name)) {
|
||||
headerValue = String.valueOf(headerMap.get(name));
|
||||
}
|
||||
return headerValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the Header names
|
||||
*/
|
||||
@Override
|
||||
public Enumeration<String> getHeaderNames() {
|
||||
List<String> names = Collections.list(super.getHeaderNames());
|
||||
for (Object name : headerMap.keySet()) {
|
||||
names.add(String.valueOf(name));
|
||||
}
|
||||
return Collections.enumeration(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaders(String name) {
|
||||
List<String> values = Collections.list(super.getHeaders(name));
|
||||
if (headerMap.containsKey(name)) {
|
||||
Object value = headerMap.get(name);
|
||||
if (String.class.isInstance(value)) {
|
||||
values.add(String.valueOf(value));
|
||||
} else if (value != null) {
|
||||
values = (List<String>) value;
|
||||
}
|
||||
}
|
||||
return Collections.enumeration(values);
|
||||
}
|
||||
}
|
|
@ -18,21 +18,27 @@ package me.zhengjie.modules.security.security;
|
|||
import cn.hutool.core.util.StrUtil;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import me.zhengjie.modules.security.config.bean.SecurityProperties;
|
||||
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||
import me.zhengjie.modules.security.service.UserCacheManager;
|
||||
import me.zhengjie.modules.security.service.dto.OnlineUserDto;
|
||||
import me.zhengjie.modules.security.service.OnlineUserService;
|
||||
import me.zhengjie.utils.HttpUtil;
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import me.zhengjie.wrapper.HeaderMapRequestWrapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -64,6 +70,8 @@ public class TokenFilter extends GenericFilterBean {
|
|||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
|
||||
throws IOException, ServletException {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
|
||||
HeaderMapRequestWrapper reqWrapper = new HeaderMapRequestWrapper((HttpServletRequest) servletRequest);
|
||||
|
||||
String token = resolveToken(httpServletRequest);
|
||||
// 对于 Token 为空的不需要去查 Redis
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
|
@ -84,9 +92,13 @@ public class TokenFilter extends GenericFilterBean {
|
|||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
// Token 续期
|
||||
tokenProvider.checkRenewal(token);
|
||||
//设置用户信息到头部
|
||||
UserDetails userDetails = SecurityUtils.getCurrentUser();
|
||||
Map<String, Object> userHeaders = HttpUtil.getUserHeaders(userDetails);
|
||||
reqWrapper.addHeaders(userHeaders);
|
||||
}
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
filterChain.doFilter(reqWrapper, servletResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue