优化SecurityUtils的方法,减少与redis之间的交互,提高性能

pull/753/head
miaoyinjun 2022-07-05 13:07:37 +08:00
parent 255a3254ce
commit 1c4741e3eb
7 changed files with 312 additions and 42 deletions

View File

@ -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);
}

View File

@ -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";
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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, "找不到当前登录的信息");
}
}

View File

@ -0,0 +1,84 @@
package me.zhengjie.wrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.*;
/**
* <p>
* requestheader
* </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);
}
}

View File

@ -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);
}
/**