mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-14 06:09:03 +08:00
♻️ Refactoring code. 优化 security模块适配最新的spring security 代码格式标准
This commit is contained in:
1 parent
6d9069f0da
commit
e74d38e9ef
6 files changed
+79
-62
No files matched your search
-2
@@ -20,7 +20,6 @@ import com.pig4cloud.pigx.common.security.component.PigxResourceServerAutoConfig
|
||||
import com.pig4cloud.pigx.common.security.component.PigxResourceServerConfiguration;
|
||||
import com.pig4cloud.pigx.common.security.feign.PigxFeignClientConfiguration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@@ -34,7 +33,6 @@ import java.lang.annotation.*;
|
||||
@Inherited
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@Import({ PigxResourceServerAutoConfiguration.class, PigxResourceServerConfiguration.class,
|
||||
PigxFeignClientConfiguration.class })
|
||||
public @interface EnablePigxResourceServer {
|
||||
|
||||
+22
-9
@@ -16,16 +16,21 @@
|
||||
|
||||
package com.pig4cloud.pigx.common.security.component;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
@@ -35,6 +40,7 @@ import org.springframework.security.web.SecurityFilterChain;
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class PigxResourceServerConfiguration {
|
||||
|
||||
@@ -49,15 +55,22 @@ public class PigxResourceServerConfiguration {
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
AntPathRequestMatcher[] requestMatchers = permitAllUrl.getIgnoreUrls()
|
||||
.stream()
|
||||
.map(AntPathRequestMatcher::new)
|
||||
.collect(Collectors.toList())
|
||||
.toArray(new AntPathRequestMatcher[] {});
|
||||
|
||||
http.authorizeHttpRequests(authorizeRequests -> authorizeRequests
|
||||
.antMatchers(ArrayUtil.toArray(permitAllUrl.getIgnoreUrls(), String.class)).permitAll().anyRequest()
|
||||
.authenticated())
|
||||
.oauth2ResourceServer(
|
||||
oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector))
|
||||
.authenticationEntryPoint(resourceAuthExceptionEntryPoint)
|
||||
.bearerTokenResolver(pigxBearerTokenExtractor))
|
||||
.headers().frameOptions().disable().and().csrf().disable();
|
||||
http.authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers(requestMatchers)
|
||||
.permitAll()
|
||||
.anyRequest()
|
||||
.authenticated())
|
||||
.oauth2ResourceServer(
|
||||
oauth2 -> oauth2.opaqueToken(token -> token.introspector(customOpaqueTokenIntrospector))
|
||||
.authenticationEntryPoint(resourceAuthExceptionEntryPoint)
|
||||
.bearerTokenResolver(pigxBearerTokenExtractor))
|
||||
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
||||
.csrf(AbstractHttpConfigurer::disable);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
+7
-9
@@ -19,18 +19,17 @@ package com.pig4cloud.pigx.common.security.component;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
|
||||
import com.pig4cloud.pigx.common.security.annotation.Inner;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* @author lengleng
|
||||
* @date 2022-06-04
|
||||
@@ -45,19 +44,18 @@ public class PigxSecurityInnerAspect implements Ordered {
|
||||
private final HttpServletRequest request;
|
||||
|
||||
@SneakyThrows
|
||||
@Around("@within(inner) || @annotation(inner)")
|
||||
public Object around(ProceedingJoinPoint point, Inner inner) {
|
||||
// 实际注入的inner实体由表达式后一个注解决定,即是方法上的@Inner注解实体,若方法上无@Inner注解,则获取类上的
|
||||
@Before("@within(inner) || @annotation(inner)")
|
||||
public void around(JoinPoint point, Inner inner) {
|
||||
String header = request.getHeader(SecurityConstants.FROM);
|
||||
if (inner == null) {
|
||||
Class<?> clazz = point.getTarget().getClass();
|
||||
inner = AnnotationUtils.findAnnotation(clazz, Inner.class);
|
||||
}
|
||||
String header = request.getHeader(SecurityConstants.FROM);
|
||||
|
||||
if (inner.value() && !StrUtil.equals(SecurityConstants.FROM_IN, header)) {
|
||||
log.warn("访问接口 {} 没有权限", point.getSignature().getName());
|
||||
throw new AccessDeniedException("Access is denied");
|
||||
}
|
||||
return point.proceed();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-11
@@ -46,35 +46,38 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS
|
||||
if (isState(authorization)) {
|
||||
String token = authorization.getAttribute("state");
|
||||
redisTemplate.setValueSerializer(RedisSerializer.java());
|
||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT,
|
||||
TimeUnit.MINUTES);
|
||||
redisTemplate.opsForValue()
|
||||
.set(buildKey(OAuth2ParameterNames.STATE, token), authorization, TIMEOUT, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
if (isCode(authorization)) {
|
||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
|
||||
.getToken(OAuth2AuthorizationCode.class);
|
||||
.getToken(OAuth2AuthorizationCode.class);
|
||||
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
|
||||
long between = ChronoUnit.MINUTES.between(authorizationCodeToken.getIssuedAt(),
|
||||
authorizationCodeToken.getExpiresAt());
|
||||
redisTemplate.setValueSerializer(RedisSerializer.java());
|
||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()),
|
||||
authorization, between, TimeUnit.MINUTES);
|
||||
redisTemplate.opsForValue()
|
||||
.set(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()), authorization,
|
||||
between, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
if (isRefreshToken(authorization)) {
|
||||
OAuth2RefreshToken refreshToken = authorization.getRefreshToken().getToken();
|
||||
long between = ChronoUnit.SECONDS.between(refreshToken.getIssuedAt(), refreshToken.getExpiresAt());
|
||||
redisTemplate.setValueSerializer(RedisSerializer.java());
|
||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()),
|
||||
authorization, between, TimeUnit.SECONDS);
|
||||
redisTemplate.opsForValue()
|
||||
.set(buildKey(OAuth2ParameterNames.REFRESH_TOKEN, refreshToken.getTokenValue()), authorization, between,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
if (isAccessToken(authorization)) {
|
||||
OAuth2AccessToken accessToken = authorization.getAccessToken().getToken();
|
||||
long between = ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt());
|
||||
redisTemplate.setValueSerializer(RedisSerializer.java());
|
||||
redisTemplate.opsForValue().set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()),
|
||||
authorization, between, TimeUnit.SECONDS);
|
||||
redisTemplate.opsForValue()
|
||||
.set(buildKey(OAuth2ParameterNames.ACCESS_TOKEN, accessToken.getTokenValue()), authorization, between,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
// 扩展记录 access-token 、username 的关系 1::token::username::admin::xxx
|
||||
String tokenUsername = String.format("%s::%s::%s::%s::%s", tenantKeyStrResolver.key(), AUTHORIZATION,
|
||||
@@ -95,7 +98,7 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS
|
||||
|
||||
if (isCode(authorization)) {
|
||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
|
||||
.getToken(OAuth2AuthorizationCode.class);
|
||||
.getToken(OAuth2AuthorizationCode.class);
|
||||
OAuth2AuthorizationCode authorizationCodeToken = authorizationCode.getToken();
|
||||
keys.add(buildKey(OAuth2ParameterNames.CODE, authorizationCodeToken.getTokenValue()));
|
||||
}
|
||||
@@ -143,7 +146,7 @@ public class PigxRedisOAuth2AuthorizationService implements OAuth2AuthorizationS
|
||||
|
||||
private static boolean isCode(OAuth2Authorization authorization) {
|
||||
OAuth2Authorization.Token<OAuth2AuthorizationCode> authorizationCode = authorization
|
||||
.getToken(OAuth2AuthorizationCode.class);
|
||||
.getToken(OAuth2AuthorizationCode.class);
|
||||
return Objects.nonNull(authorizationCode);
|
||||
}
|
||||
|
||||
|
||||
+31
-25
@@ -57,7 +57,6 @@ public class PigxRemoteRegisteredClientRepository implements RegisteredClientRep
|
||||
*/
|
||||
@Override
|
||||
public void save(RegisteredClient registeredClient) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,46 +88,53 @@ public class PigxRemoteRegisteredClientRepository implements RegisteredClientRep
|
||||
public RegisteredClient findByClientId(String clientId) {
|
||||
|
||||
SysOauthClientDetails clientDetails = RetOps
|
||||
.of(clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN)).getData()
|
||||
.orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException(
|
||||
new OAuth2Error("客户端查询异常,请检查数据库链接"), null));
|
||||
.of(clientDetailsService.getClientDetailsById(clientId, SecurityConstants.FROM_IN))
|
||||
.getData()
|
||||
.orElseThrow(() -> new OAuth2AuthorizationCodeRequestAuthenticationException(
|
||||
new OAuth2Error("客户端查询异常,请检查数据库链接"), null));
|
||||
|
||||
RegisteredClient.Builder builder = RegisteredClient.withId(clientDetails.getClientId())
|
||||
.clientId(clientDetails.getClientId())
|
||||
.clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret())
|
||||
.clientAuthenticationMethods(clientAuthenticationMethods -> {
|
||||
clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
|
||||
clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_POST);
|
||||
});
|
||||
.clientId(clientDetails.getClientId())
|
||||
.clientSecret(SecurityConstants.NOOP + clientDetails.getClientSecret())
|
||||
.clientAuthenticationMethods(clientAuthenticationMethods -> {
|
||||
clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
|
||||
clientAuthenticationMethods.add(ClientAuthenticationMethod.CLIENT_SECRET_POST);
|
||||
});
|
||||
// 授权模式
|
||||
Arrays.stream(clientDetails.getAuthorizedGrantTypes())
|
||||
.forEach(grant -> builder.authorizationGrantType(new AuthorizationGrantType(grant)));
|
||||
.forEach(grant -> builder.authorizationGrantType(new AuthorizationGrantType(grant)));
|
||||
|
||||
// 回调地址
|
||||
Optional.ofNullable(clientDetails.getWebServerRedirectUri()).ifPresent(redirectUri -> Arrays
|
||||
.stream(redirectUri.split(StrUtil.COMMA)).filter(StrUtil::isNotBlank).forEach(builder::redirectUri));
|
||||
Optional.ofNullable(clientDetails.getWebServerRedirectUri())
|
||||
.ifPresent(redirectUri -> Arrays.stream(redirectUri.split(StrUtil.COMMA))
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.forEach(builder::redirectUri));
|
||||
|
||||
// scope
|
||||
Optional.ofNullable(clientDetails.getScope()).ifPresent(
|
||||
scope -> Arrays.stream(scope.split(StrUtil.COMMA)).filter(StrUtil::isNotBlank).forEach(builder::scope));
|
||||
Optional.ofNullable(clientDetails.getScope())
|
||||
.ifPresent(scope -> Arrays.stream(scope.split(StrUtil.COMMA))
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.forEach(builder::scope));
|
||||
|
||||
// 注入扩展配置
|
||||
Optional.ofNullable(clientDetails.getAdditionalInformation()).ifPresent(ext -> {
|
||||
Map map = JSONUtil.parseObj(ext).toBean(Map.class);
|
||||
builder.clientSettings(ClientSettings.withSettings(map).requireProofKey(false)
|
||||
.requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoapprove())).build());
|
||||
builder.clientSettings(ClientSettings.withSettings(map)
|
||||
.requireProofKey(false)
|
||||
.requireAuthorizationConsent(!BooleanUtil.toBoolean(clientDetails.getAutoapprove()))
|
||||
.build());
|
||||
});
|
||||
|
||||
return builder
|
||||
.tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.REFERENCE)
|
||||
.accessTokenTimeToLive(Duration.ofSeconds(Optional
|
||||
.ofNullable(clientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds)))
|
||||
.refreshTokenTimeToLive(
|
||||
Duration.ofSeconds(Optional.ofNullable(clientDetails.getRefreshTokenValidity())
|
||||
.orElse(refreshTokenValiditySeconds)))
|
||||
.build())
|
||||
.tokenSettings(TokenSettings.builder()
|
||||
.accessTokenFormat(OAuth2TokenFormat.REFERENCE)
|
||||
.accessTokenTimeToLive(Duration.ofSeconds(
|
||||
Optional.ofNullable(clientDetails.getAccessTokenValidity()).orElse(accessTokenValiditySeconds)))
|
||||
.refreshTokenTimeToLive(Duration.ofSeconds(Optional.ofNullable(clientDetails.getRefreshTokenValidity())
|
||||
.orElse(refreshTokenValiditySeconds)))
|
||||
.build())
|
||||
|
||||
.build();
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -28,10 +28,8 @@ public class OAuth2EndpointUtils {
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
|
||||
parameterMap.forEach((key, values) -> {
|
||||
if (values.length > 0) {
|
||||
for (String value : values) {
|
||||
parameters.add(key, value);
|
||||
}
|
||||
for (String value : values) {
|
||||
parameters.add(key, value);
|
||||
}
|
||||
});
|
||||
return parameters;
|
||||
@@ -39,7 +37,7 @@ public class OAuth2EndpointUtils {
|
||||
|
||||
public boolean matchesPkceTokenRequest(HttpServletRequest request) {
|
||||
return AuthorizationGrantType.AUTHORIZATION_CODE.getValue()
|
||||
.equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE))
|
||||
.equals(request.getParameter(OAuth2ParameterNames.GRANT_TYPE))
|
||||
&& request.getParameter(OAuth2ParameterNames.CODE) != null
|
||||
&& request.getParameter(PkceParameterNames.CODE_VERIFIER) != null;
|
||||
}
|
||||
@@ -63,7 +61,8 @@ public class OAuth2EndpointUtils {
|
||||
OAuth2RefreshToken refreshToken = authentication.getRefreshToken().getToken();
|
||||
|
||||
OAuth2AccessTokenResponse.Builder builder = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
|
||||
.tokenType(accessToken.getTokenType()).scopes(accessToken.getScopes());
|
||||
.tokenType(accessToken.getTokenType())
|
||||
.scopes(accessToken.getScopes());
|
||||
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
|
||||
builder.expiresIn(ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user