✨ common-security 能力增强,支持手动传递token 到下游服务

(cherry picked from commit df53f305efa807972f836608cbaf577ee43bc071)
This commit is contained in:
冷冷 committed 2024-05-15 12:47:09 +08:00
1 parent 812684757c
commit 116d2d664c
3 files changed
+105 -30

No files matched your search

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.WebUtils;
import com.pig4cloud.pigx.common.security.util.NonWebTokenContextHolder;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.RequiredArgsConstructor;
@@ -13,11 +14,12 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
/**
* oauth2 feign token传递
*
* <p>
* 重新 OAuth2FeignRequestInterceptor ,官方实现部分常见不适用
*
* @author lengleng
@@ -27,37 +29,41 @@ import java.util.Collection;
@RequiredArgsConstructor
public class PigxOAuthRequestInterceptor implements RequestInterceptor {
private final BearerTokenResolver tokenResolver;
private final BearerTokenResolver tokenResolver;
/**
* Create a template with the header of provided name and extracted extract </br>
*
* 1. 如果使用 非web 请求,header 区别 </br>
*
* 2. 根据authentication 还原请求token
* @param template
*/
@Override
public void apply(RequestTemplate template) {
Collection<String> fromHeader = template.headers().get(SecurityConstants.FROM);
// 带from 请求直接跳过
if (CollUtil.isNotEmpty(fromHeader) && fromHeader.contains(SecurityConstants.FROM_IN)) {
return;
}
/**
* Create a template with the header of provided name and extracted extract </br>
* <p>
* 1. 如果使用 非web 请求,header 区别 </br>
* <p>
* 2. 根据authentication 还原请求token
*
* @param template
*/
@Override
public void apply(RequestTemplate template) {
Collection<String> fromHeader = template.headers().get(SecurityConstants.FROM);
// 带from 请求直接跳过
if (CollUtil.isNotEmpty(fromHeader) && fromHeader.contains(SecurityConstants.FROM_IN)) {
return;
}
// 非web 请求直接跳过
if (WebUtils.getRequest() == null) {
return;
}
HttpServletRequest request = WebUtils.getRequest();
// 避免请求参数的 query token 无法传递
String token = tokenResolver.resolve(request);
if (StrUtil.isBlank(token)) {
return;
}
template.header(HttpHeaders.AUTHORIZATION,
String.format("%s %s", OAuth2AccessToken.TokenType.BEARER.getValue(), token));
// 非web 请求直接跳过
String token = "";
if (WebUtils.getRequest() == null) {
token = NonWebTokenContextHolder.getToken();
} else {
HttpServletRequest request = WebUtils.getRequest();
// 避免请求参数的 query token 无法传递
token = tokenResolver.resolve(request);
}
}
if (StrUtil.isBlank(token)) {
return;
}
template.header(HttpHeaders.AUTHORIZATION,
String.format("%s %s", OAuth2AccessToken.TokenType.BEARER.getValue(), token));
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.common.security.util;
import com.alibaba.ttl.TransmittableThreadLocal;
import lombok.experimental.UtilityClass;
/**
* @author lengleng
* @date 2024-04-23
* <p>
* 在非web 调用feign 传递之前手动set token
*/
@UtilityClass
public class NonWebTokenContextHolder {
private final ThreadLocal<String> THREAD_LOCAL_VERSION = new TransmittableThreadLocal<>();
/**
* TTL 设置token<br/>
*
* @param token token
*/
public void setToken(String token) {
THREAD_LOCAL_VERSION.set(token);
}
/**
* 获取TTL中的token
*
* @return
*/
public String getToken() {
return THREAD_LOCAL_VERSION.get();
}
public void clear() {
THREAD_LOCAL_VERSION.remove();
}
}
@@ -24,6 +24,7 @@ import lombok.experimental.UtilityClass;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
import java.util.ArrayList;
import java.util.Collection;
@@ -44,6 +45,18 @@ public class SecurityUtils {
return SecurityContextHolder.getContext().getAuthentication();
}
/**
* 获取Authentication Token
* @return
*/
public String getToken(){
Authentication authentication = SecurityUtils.getAuthentication();
if (authentication instanceof BearerTokenAuthentication bearerTokenAuthentication) {
return bearerTokenAuthentication.getToken().getTokenValue();
}
return null;
}
/**
* 获取用户
* @param authentication