所以,在某些背景下,你应该只抛出AuthenticationException 的原因是因为 DW 的好人提供的过滤器只处理这个异常。对于所有其他例外,这是未定义的。
详情见:AuthFilter#authenticate
但是,有一种非常简单的方法可以做你想做的事。
查看 DW 代码,你会得到:
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
final BasicCredentials credentials =
getCredentials(requestContext.getHeaders().getFirst(HttpHeaders.AUTHORIZATION));
if (!authenticate(requestContext, credentials, SecurityContext.BASIC_AUTH)) {
throw new WebApplicationException(unauthorizedHandler.buildResponse(prefix, realm));
}
}
此代码的作用是调用您的Authenticator 来解析用户,然后检查它是否已通过身份验证。如果不是,那么它将调用UnauthorizedHandler 来检查它需要什么响应。可悲的是,处理程序没有获取传入的 Principal,所以它只能返回一个静态异常。
现在,如果您想手工制作这个,这将是您的入口点。与其简单地使用他们提供的BasicCredentialAuthFilter,不如编写自己的代码来为您做正确的事情。
但是,从代码 sn-p 中,我们可以看到这个过滤器所做的只是抛出一个WebApplicationException。所以我们可以缩短这个。
我们的Authenticator 实现可以预先进行用户锁定检查并填充异常让我们绕过此行为。这样,保留了下游逻辑(对WebapplicationException 做出反应,我认为这实际上是一个球衣 feautere(请参阅:异常映射器))。
所以,考虑这个例子:
public class AuthenticatorTest extends io.dropwizard.Application<Configuration> {
@Override
public void run(Configuration configuration, Environment environment) throws Exception {
environment.jersey().register(new MyHelloResource());
UserAuth a = new UserAuth();
environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<Principal>()
.setAuthenticator(a).setRealm("SUPER SECRET STUFF").buildAuthFilter()));
}
public static void main(String[] args) throws Exception {
new AuthenticatorTest().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test.yaml");
}
@Path("test")
@Produces(MediaType.APPLICATION_JSON)
public static class MyHelloResource {
@GET
@Path("asd")
@PermitAll
public String test(String x) {
return "Hello";
}
}
public static class UserAuth implements Authenticator<BasicCredentials, Principal> {
@Override
public Optional<Principal> authenticate(BasicCredentials credentials) throws AuthenticationException {
throw new WebApplicationException(Response.status(403).entity("User is blocked").build());
}
}
}
此代码只是创建一个新异常,而不是验证用户名。这导致了这个卷曲:
artur@pandaadb:/$ curl "artur:artur@localhost:9085/api/test/asd"
User is blockedartur@pandaadb:/$ curl "artur:artur@localhost:9085/api/test/asd" -v
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9085 (#0)
* Server auth using Basic with user 'artur'
> GET /api/test/asd HTTP/1.1
> Host: localhost:9085
> Authorization: Basic YXJ0dXI6YXJ0dXI=
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 403 Forbidden
< Date: Thu, 12 Jan 2017 14:19:27 GMT
< Content-Type: application/json
< Content-Length: 15
<
* Connection #0 to host localhost left intact
User is blocked
现在,这可能不是您能做的最干净的解决方案。如果您需要快速执行此操作,则可以将异常从Authenticator 中抛出。但是,正确的做法是:
- 基于
io.dropwizard.auth.AuthFilter 实现一个新的 AuthFilter
- 覆盖
AuthFilter 上的身份验证方法以检查您的用户并在那里抛出正确的异常。