如何修改 Micronaut Http 过滤器的顺序,使其在 Micronaut Security

问题描述

我有一个 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 方法,但没有用 :(

解决方法

您没有指定您使用的是哪个 Micronaut 版本,但答案是该行为是一个错误。它应该在 Micronaut 2.5.4 中按预期工作