初始化
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
package com.njcn.gateway.config;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.njcn.common.pojo.constant.SecurityConstants;
|
||||
import com.njcn.gateway.enums.GateWayEnum;
|
||||
import com.njcn.gateway.security.AuthorizationManager;
|
||||
import com.njcn.gateway.utils.ResponseUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
|
||||
/**
|
||||
* @author hongawen
|
||||
* 资源服务器配置
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Configuration
|
||||
@EnableWebFluxSecurity
|
||||
public class ResourceServerConfig {
|
||||
|
||||
private final AuthorizationManager authorizationManager;
|
||||
|
||||
private final WhiteListConfig whiteListConfig;
|
||||
|
||||
@Bean
|
||||
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
|
||||
|
||||
http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter())
|
||||
// 本地获取公钥
|
||||
.publicKey(rsaPublicKey());
|
||||
|
||||
http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());
|
||||
|
||||
http.oauth2ResourceServer().authenticationEntryPoint(authenticationEntryPoint());
|
||||
|
||||
http.authorizeExchange()
|
||||
.pathMatchers(Convert.toStrArray(whiteListConfig.getUrls())).permitAll()
|
||||
.anyExchange().access(authorizationManager)
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
// 处理未授权
|
||||
.accessDeniedHandler(accessDeniedHandler())
|
||||
// 处理未认证
|
||||
.authenticationEntryPoint(authenticationEntryPoint())
|
||||
.and().csrf().disable();
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 访问拒绝处理器
|
||||
*/
|
||||
@Bean
|
||||
ServerAccessDeniedHandler accessDeniedHandler() {
|
||||
return (exchange, denied) -> Mono.defer(() -> Mono.just(exchange.getResponse()))
|
||||
.flatMap(response -> ResponseUtils.writeErrorInfo(response, GateWayEnum.NO_AUTHORIZATION));
|
||||
}
|
||||
|
||||
/**
|
||||
* token无效或者已过期自定义响应
|
||||
*/
|
||||
@Bean
|
||||
ServerAuthenticationEntryPoint authenticationEntryPoint() {
|
||||
return (exchange, e) -> Mono.defer(() -> Mono.just(exchange.getResponse()))
|
||||
.flatMap(response -> ResponseUtils.writeErrorInfo(response, GateWayEnum.ACCESS_TOKEN_EXPIRE_JWT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://blog.csdn.net/qq_24230139/article/details/105091273
|
||||
* ServerHttpSecurity没有将jwt中authorities的负载部分当做Authentication
|
||||
* 需要把jwt的Claim中的authorities加入
|
||||
* 方案:重新定义权限管理器,默认转换器JwtGrantedAuthoritiesConverter
|
||||
*/
|
||||
@Bean
|
||||
public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
|
||||
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
|
||||
jwtGrantedAuthoritiesConverter.setAuthorityPrefix(SecurityConstants.AUTHORITY_PREFIX);
|
||||
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(SecurityConstants.JWT_AUTHORITIES_KEY);
|
||||
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
||||
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
|
||||
return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地获取JWT验签公钥
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Bean
|
||||
public RSAPublicKey rsaPublicKey() {
|
||||
Resource resource = new ClassPathResource("public.key");
|
||||
InputStream is = resource.getInputStream();
|
||||
String publicKeyData = IoUtil.read(is).toString();
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec((Base64.decode(publicKeyData)));
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
||||
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user