我有一个 checkForBankId 注释
@Target(value = { ElementType.METHOD, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(value=RetentionPolicy.RUNTIME)
public @interface checkForBankId {
boolean ignore() default false;
}
我有一个 BankIdSecurityService
public class BankIdSecurityService {
/*
* This is declarative client to call the
* InternalAPIs to get all details about the user;
*/
@Inject
UserRepositoryClient client;
static final boolean AUTHORIZED = true;
static final boolean UnAUTHENTICATED = false;
Flowable<Boolean> checkAuthentication(HttpRequest<?> request) {
if (routeMatch instanceof MethodBasedRouteMatch) {
MethodBasedRouteMatch<?, ?> methodBasedRouteMatch =
(MethodBasedRouteMatch<?, ?>) routeMatch;
if (methodBasedRouteMatch.hasAnnotation(checkForBankId.class)) {
String userName = getUserName(request).get();
if(!request.getParameter().contains("bankId")) {
return Flowable.just(UNAUTHORIZED);
}
return this.client.getUser(userName).map(userDetails -> {
String bankId = request.getParameter().get("bankId");
BankAccount[] bankAccounts = userDetails.getPayload().getBankAccounts();
boolean bankIdFound = false;
for(BankAcconut bankAccout: bankAccounts) {
if(bankAccount.getId().equals(bankId)) {
bankIdFound = true;
break;
}
}
return bankIdFound ? AUTHENTICATED : UNAUTHORIZED;
});
}
}
return Flowable.just(AUTHENTICATED);
}
Optional<String> getUserName(HttpRequest<?> request) {
// get jwt from request header
then parse the jwt and extract
the username from it and return;
}
}
然后我有过滤器,每个请求执行一次
@Filter(Filter.MATCH_ALL_PATTERN)
@AllArgsConstructor
@Slf4j
public class BankIdSecurityFilter extends OncePerRequestHttpServerFilter {
private final BankIdSecurityService bankIdSecurityService;
@Override
protected Publisher<MutableHttpResponse<?>> doFilterOnce(
HttpRequest<?> request, ServerFilterChain chain
) {
log.info("request route: {}", request);
return this.bankIdSecurityService
.checkAuthentication(request).switchMap(authResult -> {
log.info("authentication result: {}", authResult);
return authResult ? // if authResult is true then proceed as usual
chain.proceed(request) :
Publishers.just(HttpResponse.status(HttpStatus.BAD_REQUEST)
.body("This bankId doesn't belond to this user.")
); // return bad request
});
}
@Override
public int getOrder() {
return ServerFilterPhase.SECURITY.after();
}
}
在控制器内部,我们在要过滤请求的地方应用@CheckForBankId
@CheckForBankId
@GET("get-bank-account?{bankId}")
Single<BankAccount> getBankAccount(String bankId) {
return someService.getBankAccount(bankId);
}
过滤器工作正常。缺少的是它在 microanut 安全性之前执行,因此,进入标头的令牌未经身份验证,在某些情况下,它可能导致一些问题,例如如果将过期令牌传递给标头并且我的解析器将解析令牌并将从中返回用户,但由于令牌已经无效,因此没有任何意义。它应该在进入过滤器之前已经被拒绝......所以,就像这个过滤器在 micronaut 安全之后执行。我尝试覆盖 getOrder 方法,但它不起作用:(