Java 通过基本身份验证端点创建JSON Web令牌?Dropwizard

Java 通过基本身份验证端点创建JSON Web令牌?Dropwizard,java,jwt,dropwizard,Java,Jwt,Dropwizard,使用Dropwizard 1.2.0和,我试图从名为/tokenAPI端点创建json web令牌 此端点要求客户端使用基本身份验证方法传递用户名和密码。如果成功,响应将包含JSON web令牌 负责人 public class ShepherdAuth implements JwtCookiePrincipal { private String name; private Set<String> roles; public ShepherdAuth(String name, S

使用Dropwizard 1.2.0和,我试图从名为
/token
API端点创建json web令牌

此端点要求客户端使用基本身份验证方法传递用户名和密码。如果成功,响应将包含JSON web令牌

负责人

public class ShepherdAuth implements JwtCookiePrincipal {

private String name;
private Set<String> roles;

public ShepherdAuth(String name, Set<String> roles) {
    this.name = checkNotNull(name, "User name is required");
    this.roles = checkNotNull(roles, "Roles are required");
}

@Override
public boolean isPersistent() {
    return false;
}

@Override
public boolean isInRole(final String s) {
    return false;
}

@Override
public String getName() {
    return this.name;
}

@Override
public boolean implies(Subject subject) {
    return false;
}

public Set<String> getRoles() {
    return roles;
}
}
App/Config

    @Override
public void run(final ShepherdServiceConfiguration configuration,
                final Environment environment) {

    final ShepherdController shepherdController = new ShepherdController();

    // app authentication
    environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<ShepherdAuth>()
            .setAuthenticator(new ShepherdAuthenticator())
            .setAuthorizer(new ShepherdAuthorizer())
            .setRealm(configuration.getName())
            .buildAuthFilter()));
@覆盖
公共无效运行(最终ShepherdServiceConfiguration配置,
最终环境(环境){
最终ShepherdController ShepherdController=新的ShepherdController();
//应用程序身份验证
environment.jersey().register(新的AuthDynamicFeature(新的BasicCredentialAuthFilter.Builder())
.setAuthenticator(新的ShepherdAuthenticator())
.setAuthorizer(新的牧羊人授权人())
.setRealm(配置.getName())
.buildAuthFilter());
当我尝试向
/shepherd/token
发出请求时,我没有收到关于基本身份验证的提示,而是收到一个HTTP 401响应,其中包含

访问此资源需要凭据


如何让控制器提示输入用户名和密码,并在成功时生成JWT?

我在项目中通过使用实现了JWT令牌,但解决方案很容易应用到另一个库。诀窍是使用不同的身份验证程序

这个答案不适用于,但在为Dropwizard提供JWT方面做得很好:)

首先,申请:

environment.jersey().register(new TokenResource(configuration.getJwsSecretKey()));
environment.jersey().register(new HelloResource());
environment.jersey().register(RolesAllowedDynamicFeature.class);
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
environment.jersey()
    .register(
        new AuthDynamicFeature(
            new ChainedAuthFilter<>(
                Arrays
                    .asList(
                        new JWTCredentialAuthFilter.Builder<User>()
                            .setAuthenticator(
                                new JWTAuthenticator(configuration.getJwsSecretKey()))
                            .setPrefix("Bearer").setAuthorizer(new UserAuthorizer())
                            .buildAuthFilter(),
                        new JWTDefaultCredentialAuthFilter.Builder<User>()
                            .setAuthenticator(new JWTDefaultAuthenticator())
                            .setAuthorizer(new UserAuthorizer()).setRealm("SUPER SECRET STUFF")
                            .buildAuthFilter()))));
这里,
TokenResource
是令牌供应资源,
HelloResource
是我们的测试资源。
User
是主体,如下所示:

public class User implements Principal {
  private String name;
  private String password;
  ...
}
还有一个类用于传递JWT令牌:

public class JWTCredentials {
  private String jwtToken;
  ...
}
TokenResource
使用密码“test”为用户“test”提供令牌:

HelloResource
只是回显用户:

@GET
@RolesAllowed({"ANY"})
public String hello(@Auth User user) {
  return "hello user \"" + user.getName() + "\"";
}
JWTCredentialAuthFilter
为两种身份验证方案提供凭据:

@Priority(Priorities.AUTHENTICATION)
public class JWTCredentialAuthFilter<P extends Principal> extends AuthFilter<JWTCredentials, P> {

  public static class Builder<P extends Principal>
      extends AuthFilterBuilder<JWTCredentials, P, JWTCredentialAuthFilter<P>> {

    @Override
    protected JWTCredentialAuthFilter<P> newInstance() {
      return new JWTCredentialAuthFilter<>();
    }
  }

  @Override
  public void filter(ContainerRequestContext requestContext) throws IOException {
    final JWTCredentials credentials =
    getCredentials(requestContext.getHeaders().getFirst(HttpHeaders.AUTHORIZATION));
    if (!authenticate(requestContext, credentials, "JWT")) {
      throw new WebApplicationException(
          this.unauthorizedHandler.buildResponse(this.prefix, this.realm));
    }
  }

  private static JWTCredentials getCredentials(String authLine) {
    if (authLine != null && authLine.startsWith("Bearer ")) {
      JWTCredentials result = new JWTCredentials();
      result.setJwtToken(authLine.substring(7));
      return result;
    }
    return null;
  }
}
JWTDefaultAuthenticator
在不存在凭据时,为代码提供一个空用户:

public class JWTDefaultAuthenticator implements Authenticator<JWTCredentials, User> {

  @Override
  public Optional<User> authenticate(JWTCredentials credentials) throws AuthenticationException {
    return Optional.of(new User());
  }
}
如果一切顺利

curl -s -X POST -d 'test' http://localhost:8080/token/test
将为您提供如下信息:

eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDk3MDYwMjYsInN1YiI6InRlc3QifQ.ZrRmWTUDpaA6JlU4ysIcFllxtqvUS2OPbCMJgyou_tY
这个问题呢

curl -s -X POST -d 'xtest' http://localhost:8080/token/test
将以失败告终

{"code":401,"message":"HTTP 401 Unauthorized"}
(顺便说一句,URL中的“test”是用户名,post数据中的“test”是密码。与基本身份验证一样简单,可以为CORS配置。)

请求呢

curl -s -X GET -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDk3MDYwMjYsInN1YiI6InRlc3QifQ.ZrRmWTUDpaA6JlU4ysIcFllxtqvUS2OPbCMJgyou_tY' http://localhost:8080/hello
将显示

hello user "test"

将导致

{"code":403,"message":"User not authorized."}

您的配置中缺少此行


environment.jersey().register(新AuthValueFactoryProvider.Binder(User.class));

谢谢,但此库不稳定,仅为0.9.0版:(两件事:不要让版本误导您,我知道Dropwizard在版本1之前已经用于许多不同的生产环境。其次,Dropwizard JWT库使用同一个库。请检查它的pom.xml。谢谢,我尝试了您的解决方案,但它说它找不到
JWTCredentials
类,我必须这样做吗由另一个库提供?我的不好。编辑了答案以包含它。它只是一个仅具有
jwtToken
属性的POJO。感谢您的帮助,是否仍然可以使用
TokenResource
而不是DefaultJWTAuthenticator的基本身份验证?我尝试将
BasicCredentialAuthFilter
添加到身份验证器列表b中尝试使用该端点获取令牌时,Dropwizard没有提示登录。有什么想法吗?
eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDk3MDYwMjYsInN1YiI6InRlc3QifQ.ZrRmWTUDpaA6JlU4ysIcFllxtqvUS2OPbCMJgyou_tY
curl -s -X POST -d 'xtest' http://localhost:8080/token/test
{"code":401,"message":"HTTP 401 Unauthorized"}
curl -s -X GET -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDk3MDYwMjYsInN1YiI6InRlc3QifQ.ZrRmWTUDpaA6JlU4ysIcFllxtqvUS2OPbCMJgyou_tY' http://localhost:8080/hello
hello user "test"
curl -s -X GET -H 'Authorization: Bearer invalid' http://localhost:8080/hello
curl -s -X GET http://localhost:8080/hello
{"code":403,"message":"User not authorized."}