JAX-RS:自定义 SecurityContext 在注入资源方法时具有意外类型

JAX-RS: Custom SecurityContext has unexpected type when injected into resource method

我已经实现了一个 ContainerRequestFilter 来执行基于 JWT 的身份验证:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        AuthenticationResult authResult = ...
        if (authResult.isSuccessful()) {
            // Client successfully authenticated.
            // Now update the security context to be the augmented security context that contains information read from the JWT.
            requestContext.setSecurityContext(new JwtSecurityContect(...));
        } else {
            // Client provided no or an invalid authentication token.
            // Deny request by sending a 401 response.
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
        }
    }
}

如您所见,我更新了请求的 SecurityContext,如果身份验证成功,将其设置为我自己的自定义实现 (JwtSecurityContext) 的实例。此实现添加了额外的身份验证和授权数据,我想稍后在我的后续过滤器和我的资源方法中访问这些数据。

我还实现了 AuthorizationFilter,它会在 AuthenticationFilter 之后立即调用。在这里,我可以访问更新后的 JwtSecurityContext 就好了。

但是,当我尝试将 JwtSecurityContext 注入资源(方法)时遇到问题。

我目前正在使用 Jersey,I've read the following in its documentation:

The SecurityContext can be directly retrieved from ContainerRequestContext via getSecurityContext() method. You can also replace the default SecurityContext in a request context with a custom one using the setSecurityContext(SecurityContext) method. If you set a custom SecurityContext instance in your ContainerRequestFilter, this security context instance will be used for injection into JAX-RS resource class fields. This way you can implement a custom authentication filter that may setup your own SecurityContext to be used. To ensure the early execution of your custom authentication request filter, set the filter priority to AUTHENTICATION using constants from Priorities. An early execution of you authentication filter will ensure that all other filters, resources, resource methods and sub-resource locators will execute with your custom SecurityContext instance.

我尝试将 JwtSecurityContext 注入资源方法,如下所示:

@Path("/somepath")
public class SomeResource {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<SomeItem> getItems(@Context SecurityContext securityContext) {
        // securityContext is of type 'SecurityContextInjectee'
    }
}

如注释所示,securityContext 变量的运行时类型变为 SecurityContextInjectee。通过调试,我观察到它包装了一个 ContainerRequest,它又包装了我的 JwtSecurityContext。但是,没有 getter,我不想使用反射来深入了解这个对象层次结构,所以我不知道如何获取我的 JwtSecurityContext.

我曾尝试将 @Context SecurityContext securityContext 更改为 @Context JwtSecurityContext jwtSecurityContext,但如果我这样做,变量将变为 null。我也尝试过字段注入,但它的行为方式相同。

我走错路了吗?我不应该在我的资源方法中访问我的自定义 SecurityContext 吗?一种替代方法是将我的所有数据包装在 Principal 实现中,我 return 来自 getUserPrincipal 在我的 JwtSecurityContext 中。我想代理 (SecurityContextInjectee) 会将调用转发到其基础 JwtSecurityContext,因此 return 我的 Principal,但我不确定,最终我更愿意使用我的 JwtSecurityContext 而不是将这些值包装在 Principal 实现中。

您可以注入 ContainerRequestContext(如 this post 中所述)并从那里获取 SecurityContext

public List<SomeItem> getItems(@Context ContainerRequestContext context) {
    JwtSecurityContext sec = (JwtSecurityContext)context.getSecurityContext();
}