mirror of
https://gitee.com/youlaitech/youlai-mall.git
synced 2024-12-23 13:03:43 +08:00
网关整个nacos和oauth2认证资源授权测试
This commit is contained in:
parent
ef56771a05
commit
affa6880b2
@ -23,7 +23,7 @@ public class ResourceRoleRulesHolder {
|
|||||||
Map<String, List<String>> resourceRoleMap = new TreeMap<>();
|
Map<String, List<String>> resourceRoleMap = new TreeMap<>();
|
||||||
List<String> roleNames = new ArrayList<>();
|
List<String> roleNames = new ArrayList<>();
|
||||||
roleNames.add(AuthConstant.AUTHORITY_PREFIX + "1_root");
|
roleNames.add(AuthConstant.AUTHORITY_PREFIX + "1_root");
|
||||||
resourceRoleMap.put("/youlai-service/users", roleNames);
|
resourceRoleMap.put("/admin/users", roleNames);
|
||||||
redisTemplate.delete(AuthConstant.RESOURCE_ROLES_MAP_KEY);
|
redisTemplate.delete(AuthConstant.RESOURCE_ROLES_MAP_KEY);
|
||||||
redisTemplate.opsForHash().putAll(AuthConstant.RESOURCE_ROLES_MAP_KEY, resourceRoleMap);
|
redisTemplate.opsForHash().putAll(AuthConstant.RESOURCE_ROLES_MAP_KEY, resourceRoleMap);
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ public class SysUserController {
|
|||||||
if(sysUser!=null){
|
if(sysUser!=null){
|
||||||
BeanUtil.copyProperties(sysUser,userDTO);
|
BeanUtil.copyProperties(sysUser,userDTO);
|
||||||
List<Integer> roleIds = iSysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>()
|
List<Integer> roleIds = iSysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>()
|
||||||
.eq(SysUserRole::getUserId, sysUser)
|
.eq(SysUserRole::getUserId, sysUser.getId())
|
||||||
).stream().map(item -> item.getRoleId()).collect(Collectors.toList());
|
).stream().map(item -> item.getRoleId()).collect(Collectors.toList());
|
||||||
if(CollectionUtil.isNotEmpty(roleIds)){
|
if(CollectionUtil.isNotEmpty(roleIds)){
|
||||||
List<String> roles = iSysRoleService.listByIds(roleIds).stream()
|
List<String> roles = iSysRoleService.listByIds(roleIds).stream()
|
||||||
|
@ -2,50 +2,86 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>2.3.0.RELEASE</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>youlai-mall</artifactId>
|
||||||
|
<groupId>com.youlai</groupId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
<artifactId>youlai-gateway</artifactId>
|
<artifactId>youlai-gateway</artifactId>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
|
<youlai-common.version>1.0.0-SNAPSHOT</youlai-common.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.youlai</groupId>
|
||||||
|
<artifactId>youlai-admin-api</artifactId>
|
||||||
|
<version>${youlai-common.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.youlai</groupId>
|
||||||
|
<artifactId>youlai-common-core</artifactId>
|
||||||
|
<version>${youlai-common.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.youlai</groupId>
|
||||||
|
<artifactId>youlai-common-auth</artifactId>
|
||||||
|
<version>${youlai-common.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.youlai</groupId>
|
||||||
|
<artifactId>youlai-common-redis</artifactId>
|
||||||
|
<version>${youlai-common.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency>
|
|
||||||
|
<!-- nacos 依赖-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba.cloud</groupId>
|
||||||
|
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
</dependency>-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-starter-config</artifactId>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 认证依赖 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
<artifactId>spring-security-config</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-oauth2-resource-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-oauth2-jose</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.nimbusds</groupId>
|
||||||
|
<artifactId>nimbus-jose-jwt</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<!-- spring cloud -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.cloud</groupId>
|
|
||||||
<artifactId>spring-cloud-dependencies</artifactId>
|
|
||||||
<version>${spring-cloud.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
package com.youlai.gateway;
|
package com.youlai;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
@ -8,6 +7,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
|||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
public class GatewayApplication {
|
public class GatewayApplication {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(GatewayApplication.class, args);
|
SpringApplication.run(GatewayApplication.class, args);
|
||||||
}
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
package com.youlai.gateway.auth;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.nimbusds.jose.JWSObject;
|
||||||
|
import com.youlai.admin.api.dto.UserDTO;
|
||||||
|
import com.youlai.common.auth.constant.AuthConstant;
|
||||||
|
import com.youlai.gateway.config.WhiteUrlsConfig;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
|
import org.springframework.security.authorization.ReactiveAuthorizationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.web.server.authorization.AuthorizationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.util.PathMatcher;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 鉴权管理器,用于判断是否有资源的访问权限
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WhiteUrlsConfig whiteUrlsConfig;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<AuthorizationDecision> check(Mono<Authentication> mono, AuthorizationContext authorizationContext) {
|
||||||
|
ServerHttpRequest request = authorizationContext.getExchange().getRequest();
|
||||||
|
URI uri = request.getURI();
|
||||||
|
//白名单路径直接放行
|
||||||
|
PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
|
List<String> whiteUrls = whiteUrlsConfig.getUrls();
|
||||||
|
for (String ignoreUrl : whiteUrls) {
|
||||||
|
if (pathMatcher.match(ignoreUrl, uri.getPath())) {
|
||||||
|
return Mono.just(new AuthorizationDecision(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//对应跨域的预检请求直接放行
|
||||||
|
if (request.getMethod() == HttpMethod.OPTIONS) {
|
||||||
|
return Mono.just(new AuthorizationDecision(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
String token = request.getHeaders().getFirst(AuthConstant.JWT_TOKEN_HEADER);
|
||||||
|
if (StrUtil.isBlank(token)) {
|
||||||
|
return Mono.just(new AuthorizationDecision(false));
|
||||||
|
}
|
||||||
|
token = token.replace(AuthConstant.JWT_TOKEN_PREFIX, "");
|
||||||
|
JWSObject jwsObject = JWSObject.parse(token);
|
||||||
|
String payload = jwsObject.getPayload().toString(); // jwt 载体部分
|
||||||
|
UserDTO userDTO = JSONUtil.toBean(payload, UserDTO.class);
|
||||||
|
|
||||||
|
if (AuthConstant.ADMIN_CLIENT_ID.equals(userDTO.getClientId())
|
||||||
|
&& !pathMatcher.match(AuthConstant.ADMIN_URL_PATTERN, uri.getPath())) {
|
||||||
|
return Mono.just(new AuthorizationDecision(false));
|
||||||
|
}
|
||||||
|
} catch (ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return Mono.just(new AuthorizationDecision(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 非管理端路径直接放行
|
||||||
|
if (!pathMatcher.match(AuthConstant.ADMIN_URL_PATTERN, uri.getPath())) {
|
||||||
|
return Mono.just(new AuthorizationDecision(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理端路径需要校验权限
|
||||||
|
Map<Object, Object> resourceRolesMap = redisTemplate.opsForHash().entries(AuthConstant.RESOURCE_ROLES_MAP_KEY);
|
||||||
|
Iterator<Object> iterator = resourceRolesMap.keySet().iterator();
|
||||||
|
|
||||||
|
List<String> authorities = new ArrayList<>();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
String pattern = (String) iterator.next();
|
||||||
|
if (pathMatcher.match(pattern, uri.getPath())) {
|
||||||
|
authorities.addAll(Convert.toList(String.class, resourceRolesMap.get(pattern)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> finalAuthorities = authorities;
|
||||||
|
Mono<AuthorizationDecision> authorizationDecisionMono = mono
|
||||||
|
.filter(Authentication::isAuthenticated)
|
||||||
|
.flatMapIterable(Authentication::getAuthorities)
|
||||||
|
.map(GrantedAuthority::getAuthority)
|
||||||
|
.any(authorities::contains)
|
||||||
|
.map(AuthorizationDecision::new)
|
||||||
|
.defaultIfEmpty(new AuthorizationDecision(false));
|
||||||
|
|
||||||
|
return authorizationDecisionMono;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.youlai.gateway.component;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.youlai.common.result.Result;
|
||||||
|
import com.youlai.common.result.ResultCodeEnum;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义返回结果:没有登录或token过期
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class AuthServerAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
|
||||||
|
@Override
|
||||||
|
public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
|
||||||
|
ServerHttpResponse response=exchange.getResponse();
|
||||||
|
response.setStatusCode(HttpStatus.OK);
|
||||||
|
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
response.getHeaders().set("Access-Control-Allow-Origin","*");
|
||||||
|
response.getHeaders().set("Cache-Control","no-cache");
|
||||||
|
String body = JSONUtil.toJsonStr(Result.custom(ResultCodeEnum.USER_ACCOUNT_UNAUTHENTICATED));
|
||||||
|
DataBuffer buffer= response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
|
||||||
|
return response.writeWith(Mono.just(buffer));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.youlai.gateway.component;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import com.youlai.common.result.Result;
|
||||||
|
import com.youlai.common.result.ResultCodeEnum;
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ResourceServerAccessDeniedHandler implements ServerAccessDeniedHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException e) {
|
||||||
|
ServerHttpResponse response=exchange.getResponse();
|
||||||
|
response.setStatusCode(HttpStatus.OK);
|
||||||
|
response.getHeaders().set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||||
|
response.getHeaders().set("Access-Control-Allow-Origin","*");
|
||||||
|
response.getHeaders().set("Cache-Control","no-cache");
|
||||||
|
String body= JSONUtil.toJsonStr(Result.custom(ResultCodeEnum.USER_ACCESS_UNAUTHORIZED));
|
||||||
|
DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(Charset.forName("UTF-8")));
|
||||||
|
return response.writeWith(Mono.just(buffer));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.youlai.gateway.config;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
|
import com.youlai.common.auth.constant.AuthConstant;
|
||||||
|
import com.youlai.gateway.auth.AuthorizationManager;
|
||||||
|
import com.youlai.gateway.component.AuthServerAuthenticationEntryPoint;
|
||||||
|
import com.youlai.gateway.component.ResourceServerAccessDeniedHandler;
|
||||||
|
import com.youlai.gateway.filter.WhiteUrlsRemoveJwtFilter;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
|
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||||
|
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
|
||||||
|
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 reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 资源服务器配置
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Configuration
|
||||||
|
@EnableWebFluxSecurity
|
||||||
|
public class ResourceServerConfig {
|
||||||
|
|
||||||
|
private AuthorizationManager authorizationManager;
|
||||||
|
private ResourceServerAccessDeniedHandler resourceServerAccessDeniedHandler;
|
||||||
|
private AuthServerAuthenticationEntryPoint authServerAuthenticationEntryPoint;
|
||||||
|
private WhiteUrlsConfig whiteUrlsConfig;
|
||||||
|
private WhiteUrlsRemoveJwtFilter whiteUrlsRemoveJwtFilter;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
|
||||||
|
http.oauth2ResourceServer().jwt()
|
||||||
|
.jwtAuthenticationConverter(jwtAuthenticationConverter());
|
||||||
|
// 自定义处理JWT请求头过期或签名错误的结果
|
||||||
|
http.oauth2ResourceServer().authenticationEntryPoint(authServerAuthenticationEntryPoint);
|
||||||
|
// 对白名单路径,直接移除JWT请求头
|
||||||
|
http.addFilterBefore(whiteUrlsRemoveJwtFilter, SecurityWebFiltersOrder.AUTHENTICATION);
|
||||||
|
http.authorizeExchange()
|
||||||
|
.pathMatchers(ArrayUtil.toArray(whiteUrlsConfig.getUrls(),String.class)).permitAll()
|
||||||
|
.anyExchange().access(authorizationManager)
|
||||||
|
.and()
|
||||||
|
.exceptionHandling()
|
||||||
|
.accessDeniedHandler(resourceServerAccessDeniedHandler) // 处理未授权
|
||||||
|
.authenticationEntryPoint(authServerAuthenticationEntryPoint) //处理未认证
|
||||||
|
.and().csrf().disable();
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://blog.csdn.net/qq_24230139/article/details/105091273
|
||||||
|
* ServerHttpSecurity没有将jwt中authorities的负载部分当做Authentication
|
||||||
|
* 需要把jwt的Claim中的authorities加入
|
||||||
|
* 方案:重新定义ReactiveAuthenticationManager权限管理器,默认转换器JwtGrantedAuthoritiesConverter
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
|
||||||
|
JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
|
||||||
|
jwtGrantedAuthoritiesConverter.setAuthorityPrefix(AuthConstant.AUTHORITY_PREFIX);
|
||||||
|
jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(AuthConstant.AUTHORITY_CLAIM_NAME);
|
||||||
|
|
||||||
|
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
|
||||||
|
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
|
||||||
|
return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.youlai.gateway.config;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "white")
|
||||||
|
public class WhiteUrlsConfig {
|
||||||
|
private List<String> urls;
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
package com.youlai.gateway.filter;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.nimbusds.jose.JWSObject;
|
||||||
|
import com.youlai.common.auth.constant.AuthConstant;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将登录用户的JWT转换成用户信息过滤器
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||||
|
|
||||||
|
String token = exchange.getRequest().getHeaders().getFirst(AuthConstant.JWT_TOKEN_HEADER);
|
||||||
|
if (StrUtil.isBlank(token)) {
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
token = token.replace(AuthConstant.JWT_TOKEN_PREFIX, "");
|
||||||
|
JWSObject jwsObject = JWSObject.parse(token);
|
||||||
|
String userStr = jwsObject.getPayload().toString();
|
||||||
|
log.info("AuthGlobalFilter#filter,user:{}", userStr);
|
||||||
|
ServerHttpRequest request = exchange.getRequest().mutate().header(AuthConstant.USER_TOKEN_HEADER, userStr).build();
|
||||||
|
exchange = exchange.mutate().request(request).build();
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOrder() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.youlai.gateway.filter;
|
||||||
|
|
||||||
|
import com.youlai.common.auth.constant.AuthConstant;
|
||||||
|
import com.youlai.gateway.config.WhiteUrlsConfig;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.util.PathMatcher;
|
||||||
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
|
import org.springframework.web.server.WebFilter;
|
||||||
|
import org.springframework.web.server.WebFilterChain;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 白名单路径移除JWT请求头
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class WhiteUrlsRemoveJwtFilter implements WebFilter {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WhiteUrlsConfig whiteUrlsConfig;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||||
|
ServerHttpRequest request=exchange.getRequest();
|
||||||
|
URI uri=request.getURI();
|
||||||
|
PathMatcher pathMatcher=new AntPathMatcher();
|
||||||
|
|
||||||
|
//白名单路径移除JWT请求头
|
||||||
|
List<String> ignoreUrls = whiteUrlsConfig.getUrls();
|
||||||
|
for (String ignoreUrl : ignoreUrls) {
|
||||||
|
if (pathMatcher.match(ignoreUrl, uri.getPath())) {
|
||||||
|
request = exchange.getRequest().mutate().header(AuthConstant.JWT_TOKEN_HEADER, "").build();
|
||||||
|
exchange = exchange.mutate().request(request).build();
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chain.filter(exchange);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user