docs:授权服务配置注释完善

This commit is contained in:
haoxr 2020-09-20 23:52:11 +08:00
parent e1d52acda7
commit a1e53c3aba
12 changed files with 51 additions and 118 deletions

View File

@ -58,7 +58,6 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- nacos 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
@ -68,22 +67,15 @@
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -16,13 +16,17 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.and().authorizeRequests().antMatchers("/rsa/publicKey").permitAll()
.antMatchers("/v2/api-docs").permitAll()
.anyRequest().permitAll();
http
.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
.and()
.authorizeRequests().antMatchers("/rsa/publicKey").permitAll().anyRequest().authenticated()
.and()
.csrf().disable();
}
/**
* 如果不配置SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
*/
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();

View File

@ -55,8 +55,6 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!-- 认证依赖 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
@ -69,10 +67,7 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,12 +1,11 @@
package com.youlai.gateway.auth;
package com.youlai.gateway.component;
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.core.constant.AuthConstants;
import com.youlai.gateway.config.WhiteUrlsConfig;
import com.youlai.gateway.config.WhiteListConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
@ -29,7 +28,7 @@ import java.util.List;
import java.util.Map;
/**
* 鉴权管理器用于判断是否有资源的访问权限
* 鉴权管理器
*/
@Component
public class AuthorizationManager implements ReactiveAuthorizationManager<AuthorizationContext> {
@ -38,21 +37,21 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
private RedisTemplate redisTemplate;
@Autowired
private WhiteUrlsConfig whiteUrlsConfig;
private WhiteListConfig whiteListConfig;
@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();
List<String> whiteUrls = whiteListConfig.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));
}
@ -97,7 +96,7 @@ public class AuthorizationManager implements ReactiveAuthorizationManager<Author
.filter(Authentication::isAuthenticated)
.flatMapIterable(Authentication::getAuthorities)
.map(GrantedAuthority::getAuthority)
.any(roleId -> authorities.contains(roleId)) // 判断用户角色中是否有访问资源权限的角色一个就好
.any(roleId -> authorities.contains(roleId))
.map(AuthorizationDecision::new)
.defaultIfEmpty(new AuthorizationDecision(false));

View File

@ -17,10 +17,10 @@ import reactor.core.publisher.Mono;
import java.nio.charset.Charset;
/**
* 无权限访问自定义异常
* 无权访问自定义响应
*/
@Component
public class AccessDeniedHandler implements ServerAccessDeniedHandler {
public class CustomServerAccessDeniedHandler implements ServerAccessDeniedHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, AccessDeniedException e) {

View File

@ -20,7 +20,7 @@ import java.nio.charset.Charset;
* 无效token自定义异常
*/
@Component
public class AuthExceptionEntryPoint implements ServerAuthenticationEntryPoint {
public class CustomServerAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
@Override
public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {
ServerHttpResponse response=exchange.getResponse();

View File

@ -22,7 +22,7 @@ public class CorsConfig {
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}

View File

@ -3,10 +3,10 @@ package com.youlai.gateway.config;
import cn.hutool.core.util.ArrayUtil;
import com.youlai.common.core.constant.AuthConstants;
import com.youlai.gateway.auth.AuthorizationManager;
import com.youlai.gateway.component.AuthExceptionEntryPoint;
import com.youlai.gateway.component.AccessDeniedHandler;
import com.youlai.gateway.filter.WhiteUrlsRemoveJwtFilter;
import com.youlai.gateway.component.AuthorizationManager;
import com.youlai.gateway.component.CustomServerAuthenticationEntryPoint;
import com.youlai.gateway.component.CustomServerAccessDeniedHandler;
import com.youlai.gateway.filter.WhiteListRemoveJwtFilter;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -31,37 +31,36 @@ import reactor.core.publisher.Mono;
public class ResourceServerConfig {
private AuthorizationManager authorizationManager;
private AccessDeniedHandler accessDeniedHandler;
private AuthExceptionEntryPoint authExceptionEntryPoint;
private WhiteUrlsConfig whiteUrlsConfig;
private WhiteUrlsRemoveJwtFilter whiteUrlsRemoveJwtFilter;
private CustomServerAccessDeniedHandler customServerAccessDeniedHandler;
private CustomServerAuthenticationEntryPoint customServerAuthenticationEntryPoint;
private WhiteListConfig whiteListConfig;
private WhiteListRemoveJwtFilter whiteListRemoveJwtFilter;
@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.oauth2ResourceServer().jwt()
.jwtAuthenticationConverter(jwtAuthenticationConverter());
// 自定义处理JWT请求头过期或签名错误的结果
http.oauth2ResourceServer().authenticationEntryPoint(authExceptionEntryPoint);
http.oauth2ResourceServer().authenticationEntryPoint(customServerAuthenticationEntryPoint);
// 对白名单路径直接移除JWT请求头
http.addFilterBefore(whiteUrlsRemoveJwtFilter, SecurityWebFiltersOrder.AUTHENTICATION);
http.addFilterBefore(whiteListRemoveJwtFilter, SecurityWebFiltersOrder.AUTHENTICATION);
http.authorizeExchange()
.pathMatchers(ArrayUtil.toArray(whiteUrlsConfig.getUrls(),String.class)).permitAll()
.pathMatchers(ArrayUtil.toArray(whiteListConfig.getUrls(),String.class)).permitAll()
.anyExchange().access(authorizationManager)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler) // 处理未授权
.authenticationEntryPoint(authExceptionEntryPoint) //处理未认证
.accessDeniedHandler(customServerAccessDeniedHandler) // 处理未授权
.authenticationEntryPoint(customServerAuthenticationEntryPoint) //处理未认证
.and().csrf().disable();
return http.build();
}
/**
* https://blog.csdn.net/qq_24230139/article/details/105091273
* @linkhttps://blog.csdn.net/qq_24230139/article/details/105091273
* ServerHttpSecurity没有将jwt中authorities的负载部分当做Authentication
* 需要把jwt的Claim中的authorities加入
* 方案重新定义ReactiveAuthenticationManager权限管理器默认转换器JwtGrantedAuthoritiesConverter
*
* @return
*/
@Bean

View File

@ -1,15 +1,18 @@
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 {
@ConfigurationProperties(prefix = "white-list")
public class WhiteListConfig {
private List<String> urls;
}

View File

@ -14,15 +14,15 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 将登录用户的JWT转换成用户信息过滤器
* 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(AuthConstants.JWT_TOKEN_HEADER);
if (StrUtil.isBlank(token)) {
return chain.filter(exchange);

View File

@ -1,7 +1,7 @@
package com.youlai.gateway.filter;
import com.youlai.common.core.constant.AuthConstants;
import com.youlai.gateway.config.WhiteUrlsConfig;
import com.youlai.gateway.config.WhiteListConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
@ -19,10 +19,10 @@ import java.util.List;
* 白名单路径移除JWT请求头
*/
@Component
public class WhiteUrlsRemoveJwtFilter implements WebFilter {
public class WhiteListRemoveJwtFilter implements WebFilter {
@Autowired
private WhiteUrlsConfig whiteUrlsConfig;
private WhiteListConfig whiteListConfig;
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
@ -31,7 +31,7 @@ public class WhiteUrlsRemoveJwtFilter implements WebFilter {
PathMatcher pathMatcher=new AntPathMatcher();
//白名单路径移除JWT请求头
List<String> ignoreUrls = whiteUrlsConfig.getUrls();
List<String> ignoreUrls = whiteListConfig.getUrls();
for (String ignoreUrl : ignoreUrls) {
if (pathMatcher.match(ignoreUrl, uri.getPath())) {
request = exchange.getRequest().mutate().header(AuthConstants.JWT_TOKEN_HEADER, "").build();

View File

@ -1,59 +0,0 @@
package com.youlai.gateway.handler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.youlai.common.core.result.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.handler.ResponseStatusExceptionHandler;
import reactor.core.publisher.Mono;
/**
* 网关异常通用处理器只作用在webflux 环境下 , 优先级低于 {@link ResponseStatusExceptionHandler} 执行
*
* @author 冷酱
* @date 2020/5/26
*/
@Slf4j
@Order(-1)
@Configuration
@RequiredArgsConstructor
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
private final ObjectMapper objectMapper;
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
return Mono.error(ex);
}
// header set
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
if (ex instanceof ResponseStatusException) {
response.setStatusCode(((ResponseStatusException) ex).getStatus());
}
return response.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = response.bufferFactory();
try {
return bufferFactory.wrap(objectMapper.writeValueAsBytes(Result.error(ex.getMessage())));
}
catch (JsonProcessingException e) {
log.error("Error writing response", ex);
return bufferFactory.wrap(new byte[0]);
}
}));
}
}