Mis*_*toe 9 spring-security spring-webflux
我在Spring webflux上构建应用程序,并且因为Spring安全性webflux(v.M5)在异常处理方面的行为不像Spring 4而被卡住了.
我看到以下关于如何定制spring security webflux的帖子: 针对API的Spring webflux自定义身份验证
如果我们在ServerSecurityContextRepository.load中抛出异常,那么Spring会将http标头更新为500,而我无法操作此异常.
但是,控制器中抛出的任何错误都可以使用常规的@ControllerAdvice来处理,它只是弹出webflux安全性.
反正有没有处理spring webflux安全性中的异常?
我刚刚查阅了大量文档,遇到了类似的问题。
我的解决方案是使用 ResponseStatusException。Spring-security的AccessException似乎可以理解。
.doOnError(
t -> AccessDeniedException.class.isAssignableFrom(t.getClass()),
t -> AUDIT.error("Error {} {}, tried to access {}", t.getMessage(), principal, exchange.getRequest().getURI())) // if an error happens in the stream, show its message
.onErrorMap(
SomeOtherException.class,
t -> { return new ResponseStatusException(HttpStatus.NOT_FOUND, "Collection not found");})
;
Run Code Online (Sandbox Code Playgroud)
如果这对您来说是正确的方向,我可以提供更好的样本。
我发现的解决方案是创建一个实现的组件ErrorWebExceptionHandler
。ErrorWebExceptionHandler
bean 的实例在Spring Security过滤器之前运行。这是我使用的示例:
@Slf4j
@Component
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
@Autowired
private DataBufferWriter bufferWriter;
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
AppError appError = ErrorCode.GENERIC.toAppError();
if (ex instanceof AppException) {
AppException ae = (AppException) ex;
status = ae.getStatusCode();
appError = new AppError(ae.getCode(), ae.getText());
log.debug(appError.toString());
} else {
log.error(ex.getMessage(), ex);
}
if (exchange.getResponse().isCommitted()) {
return Mono.error(ex);
}
exchange.getResponse().setStatusCode(status);
return bufferWriter.write(exchange.getResponse(), appError);
}
}
Run Code Online (Sandbox Code Playgroud)
如果要注入HttpHandler
,则有点不同,但是想法是相同的。
更新:为了完整DataBufferWriter
起见,这是我的对象,它是一个@Component
:
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class DataBufferWriter {
private final ObjectMapper objectMapper;
public <T> Mono<Void> write(ServerHttpResponse httpResponse, T object) {
return httpResponse
.writeWith(Mono.fromSupplier(() -> {
DataBufferFactory bufferFactory = httpResponse.bufferFactory();
try {
return bufferFactory.wrap(objectMapper.writeValueAsBytes(object));
} catch (Exception ex) {
log.warn("Error writing response", ex);
return bufferFactory.wrap(new byte[0]);
}
}));
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
无需注册任何 bean 并更改默认的 Spring 行为。尝试更优雅的解决方案:
我们有:
方法 .load 返回 Mono
public class HttpRequestHeaderSecurityContextRepository implements ServerSecurityContextRepository {
....
@Override
public Mono<SecurityContext> load(ServerWebExchange exchange) {
List<String> tokens = exchange.getRequest().getHeaders().get("X-Auth-Token");
String token = (tokens != null && !tokens.isEmpty()) ? tokens.get(0) : null;
Mono<Authentication> authMono = reactiveAuthenticationManager
.authenticate( new HttpRequestHeaderToken(token) );
return authMono
.map( auth -> (SecurityContext)new SecurityContextImpl(auth))
}
Run Code Online (Sandbox Code Playgroud)
}
问题是:如果authMono
遗嘱包含一个error
而不是Authentication
- spring 将返回带有500状态(这意味着“未知的内部错误”)而不是401的http响应。即使错误是 AuthenticationException 或者它的子类 - 它没有意义 - Spring 将返回 500。
但我们很清楚:AuthenticationException 应该产生 401 错误......
为了解决这个问题,我们必须帮助Spring如何将异常转换为HTTP响应状态码。
为了使我们可以只使用适当的异常类:ResponseStatusException
或者仅仅是一个原始异常映射到这一个(例如,通过添加onErrorMap()
到authMono
对象)。看最后的代码:
public class HttpRequestHeaderSecurityContextRepository implements ServerSecurityContextRepository {
....
@Override
public Mono<SecurityContext> load(ServerWebExchange exchange) {
List<String> tokens = exchange.getRequest().getHeaders().get("X-Auth-Token");
String token = (tokens != null && !tokens.isEmpty()) ? tokens.get(0) : null;
Mono<Authentication> authMono = reactiveAuthenticationManager
.authenticate( new HttpRequestHeaderToken(token) );
return authMono
.map( auth -> (SecurityContext)new SecurityContextImpl(auth))
.onErrorMap(
er -> er instanceof AuthenticationException,
autEx -> new ResponseStatusException(HttpStatus.UNAUTHORIZED, autEx.getMessage(), autEx)
)
;
)
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3743 次 |
最近记录: |