refactor: SecurityUtils优化获取用户名与用户ID方式

This commit is contained in:
Jie Zheng 2025-01-14 14:58:53 +08:00
parent c31dcb671c
commit 6413e5fd87
8 changed files with 107 additions and 98 deletions

View File

@ -1,16 +0,0 @@
<template>
<elFrame :src="swaggerApi" />
</template>
<script>
import { mapGetters } from 'vuex'
import elFrame from '@/components/Iframe/index'
export default {
name: 'Swagger',
components: { elFrame },
computed: {
...mapGetters([
'swaggerApi'
])
}
}
</script>

View File

@ -16,18 +16,22 @@
package me.zhengjie.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.utils.enums.DataScopeEnum;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
/**
* 获取当前登录的用户
@ -35,8 +39,23 @@ import java.util.List;
* @date 2019-01-17
*/
@Slf4j
@Component
public class SecurityUtils {
public static String header;
public static String tokenStartWith;
@Value("${jwt.header}")
public void setHeader(String header) {
SecurityUtils.header = header;
}
@Value("${jwt.token-start-with}")
public void setTokenStartWith(String tokenStartWith) {
SecurityUtils.tokenStartWith = tokenStartWith;
}
/**
* 获取当前登录的用户
* @return UserDetails
@ -46,34 +65,6 @@ public class SecurityUtils {
return userDetailsService.loadUserByUsername(getCurrentUsername());
}
/**
* 获取系统用户名称
*
* @return 系统用户名称
*/
public static String getCurrentUsername() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期");
}
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
return userDetails.getUsername();
}
throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息");
}
/**
* 获取系统用户ID
* @return 系统用户ID
*/
public static Long getCurrentUserId() {
UserDetails userDetails = getCurrentUser();
// Java 对象转换为 JSONObject 对象
JSONObject jsonObject = (JSONObject) JSON.toJSON(userDetails);
return jsonObject.getJSONObject("user").getLong("id");
}
/**
* 获取当前用户的数据权限
* @return /
@ -97,4 +88,57 @@ public class SecurityUtils {
}
return DataScopeEnum.ALL.getValue();
}
/**
* 获取用户ID
* @return 系统用户ID
*/
public static Long getCurrentUserId() {
return getCurrentUserId(getToken());
}
/**
* 获取用户ID
* @return 系统用户ID
*/
public static Long getCurrentUserId(String token) {
JWT jwt = JWTUtil.parseToken(token);
return Long.valueOf(jwt.getPayload("userId").toString());
}
/**
* 获取系统用户名称
*
* @return 系统用户名称
*/
public static String getCurrentUsername() {
return getCurrentUsername(getToken());
}
/**
* 获取系统用户名称
*
* @return 系统用户名称
*/
public static String getCurrentUsername(String token) {
JWT jwt = JWTUtil.parseToken(token);
return jwt.getPayload("sub").toString();
}
/**
* 获取Token
* @return /
*/
public static String getToken() {
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder
.getRequestAttributes())).getRequest();
String bearerToken = request.getHeader(header);
if (bearerToken != null && bearerToken.startsWith(tokenStartWith)) {
// 去掉令牌前缀
return bearerToken.replace(tokenStartWith, "");
} else {
log.debug("非法Token{}", bearerToken);
}
return null;
}
}

View File

@ -18,7 +18,6 @@ package me.zhengjie.modules.security.config;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.security.security.*;
import me.zhengjie.modules.security.service.OnlineUserService;
import me.zhengjie.modules.security.service.UserCacheManager;
import me.zhengjie.utils.AnonTagUtils;
import me.zhengjie.utils.enums.RequestMethodEnum;
import org.springframework.context.ApplicationContext;
@ -52,7 +51,6 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
private final ApplicationContext applicationContext;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheManager userCacheManager;
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
@ -129,6 +127,6 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
}
private TokenConfigurer securityConfigurerAdapter() {
return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheManager);
return new TokenConfigurer(tokenProvider, properties, onlineUserService);
}
}

View File

@ -100,7 +100,7 @@ public class AuthController {
Authentication authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成令牌
String token = tokenProvider.createToken(authentication);
String token = tokenProvider.createToken(jwtUser);
// 将密码设置为空
jwtUser.setPassword(null);
// 返回 token 用户信息

View File

@ -18,7 +18,6 @@ package me.zhengjie.modules.security.security;
import lombok.RequiredArgsConstructor;
import me.zhengjie.modules.security.config.SecurityProperties;
import me.zhengjie.modules.security.service.OnlineUserService;
import me.zhengjie.modules.security.service.UserCacheManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.DefaultSecurityFilterChain;
@ -33,11 +32,10 @@ public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFi
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheManager userCacheManager;
@Override
public void configure(HttpSecurity http) {
TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheManager);
TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService);
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
}
}

View File

@ -16,10 +16,8 @@
package me.zhengjie.modules.security.security;
import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.security.config.SecurityProperties;
import me.zhengjie.modules.security.service.UserCacheManager;
import me.zhengjie.modules.security.service.dto.OnlineUserDto;
import me.zhengjie.modules.security.service.OnlineUserService;
import org.springframework.security.core.Authentication;
@ -32,7 +30,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;
/**
* @author /
@ -43,46 +40,34 @@ public class TokenFilter extends GenericFilterBean {
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final UserCacheManager userCacheManager;
/**
* @param tokenProvider Token
* @param properties JWT
* @param onlineUserService 用户在线
* @param userCacheManager 用户缓存工具
*/
public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService, UserCacheManager userCacheManager) {
public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService) {
this.properties = properties;
this.onlineUserService = onlineUserService;
this.tokenProvider = tokenProvider;
this.userCacheManager = userCacheManager;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String token = resolveToken(httpServletRequest);
// 对于 Token 为空的不需要去查 Redis
if (StrUtil.isNotBlank(token)) {
OnlineUserDto onlineUserDto = null;
boolean cleanUserCache = false;
try {
String loginKey = tokenProvider.loginKey(token);
onlineUserDto = onlineUserService.getOne(loginKey);
} catch (ExpiredJwtException e) {
log.error(e.getMessage());
cleanUserCache = true;
} finally {
if (cleanUserCache || Objects.isNull(onlineUserDto)) {
userCacheManager.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY)));
}
}
if (onlineUserDto != null && StringUtils.hasText(token)) {
if(StrUtil.isNotBlank(token)){
// 获取用户Token的Key
String loginKey = tokenProvider.loginKey(token);
OnlineUserDto onlineUserDto = onlineUserService.getOne(loginKey);
// 判断用户在线信息是否为空
if (onlineUserDto != null) {
// Token 续期判断
tokenProvider.checkRenewal(token);
// 获取认证信息设置上下文
Authentication authentication = tokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
// Token 续期
tokenProvider.checkRenewal(token);
}
}
filterChain.doFilter(servletRequest, servletResponse);

View File

@ -22,8 +22,10 @@ import cn.hutool.crypto.digest.DigestUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.modules.security.config.SecurityProperties;
import me.zhengjie.modules.security.service.dto.JwtUserDto;
import me.zhengjie.utils.RedisUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -40,18 +42,15 @@ import java.util.concurrent.TimeUnit;
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenProvider implements InitializingBean {
private final SecurityProperties properties;
private final RedisUtils redisUtils;
public static final String AUTHORITIES_KEY = "user";
private JwtParser jwtParser;
private JwtBuilder jwtBuilder;
public TokenProvider(SecurityProperties properties, RedisUtils redisUtils) {
this.properties = properties;
this.redisUtils = redisUtils;
}
private final RedisUtils redisUtils;
private final SecurityProperties properties;
public static final String AUTHORITIES_UUID_KEY = "uuid";
public static final String AUTHORITIES_UID_KEY = "userId";
@Override
public void afterPropertiesSet() {
@ -67,16 +66,19 @@ public class TokenProvider implements InitializingBean {
/**
* 创建Token 设置永不过期
* Token 的时间有效性转到Redis 维护
*
* @param authentication /
* @param user /
* @return /
*/
public String createToken(Authentication authentication) {
public String createToken(JwtUserDto user) {
// 设置参数
Map<String, Object> claims = new HashMap<>(6);
// 设置用户ID
claims.put(AUTHORITIES_UID_KEY, user.getUser().getId());
// 设置UUID确保每次Token不一样
claims.put(AUTHORITIES_UUID_KEY, IdUtil.simpleUUID());
return jwtBuilder
// 加入ID确保生成的 Token 都不一致
.setId(IdUtil.simpleUUID())
.claim(AUTHORITIES_KEY, authentication.getName())
.setSubject(authentication.getName())
.setClaims(claims)
.setSubject(user.getUsername())
.compact();
}

View File

@ -273,7 +273,6 @@ INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`,
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (35, 1, 3, 1, '部门管理', 'Dept', 'system/dept/index', 6, 'dept', 'dept', b'0', b'0', b'0', 'dept:list', NULL, NULL, '2019-03-25 09:46:00', NULL);
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (36, NULL, 7, 0, '系统工具', NULL, '', 30, 'sys-tools', 'sys-tools', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-29 10:57:35', NULL);
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (37, 1, 3, 1, '岗位管理', 'Job', 'system/job/index', 7, 'Steve-Jobs', 'job', b'0', b'0', b'0', 'job:list', NULL, NULL, '2019-03-29 13:51:18', NULL);
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (38, 36, 0, 1, '接口文档', 'Swagger', 'tools/swagger/index', 36, 'swagger', 'swagger2', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-29 19:57:53', NULL);
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (39, 1, 3, 1, '字典管理', 'Dict', 'system/dict/index', 8, 'dictionary', 'dict', b'0', b'0', b'0', 'dict:list', NULL, NULL, '2019-04-10 11:49:04', NULL);
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (41, 6, 0, 1, '在线用户', 'OnlineUser', 'monitor/online/index', 10, 'Steve-Jobs', 'online', b'0', b'0', b'0', NULL, NULL, NULL, '2019-10-26 22:08:43', NULL);
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (44, 2, 0, 2, '用户新增', NULL, '', 2, '', '', b'0', b'0', b'0', 'user:add', NULL, NULL, '2019-10-29 10:59:46', NULL);
@ -472,7 +471,6 @@ INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (35, 1);
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (36, 1);
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (36, 2);
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (37, 1);
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (38, 1);
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (39, 1);
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (41, 1);
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (44, 1);