Ich implementierte JWT-Token in meinem Projekt mit https://github.com/jwtk/jjwt, aber die Lösung wird problemlos auf eine andere Bibliothek angewendet werden. Der Trick besteht darin, verschiedene Authentifikatoren zu verwenden.
Diese Antwort nicht für Dropwizard JWT Library geeignet ist, aber es erfüllt seinen guten Job JWT für Dropwizard der Bereitstellung :)
Zunächst wird die Anwendung:
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()))));
Bitte beachten Sie, dass die Konfigurationsklasse eine Konfigurationseinstellung enthalten muss :
String jwsSecretKey;
Hier ist die TokenResource
Zuführen der Token-Ressource, und die i HelloResource
s unsere Testressource.User
ist das wichtigste, wie folgt aus:
public class User implements Principal {
private String name;
private String password;
...
}
Und es gibt eine Klasse der JWT-Token für die Kommunikation:
public class JWTCredentials {
private String jwtToken;
...
}
TokenResource
bietet Tokens für einen Benutzer "test" mit Passwort "test":
@POST
@Path("{user}")
@PermitAll
public String createToken(@PathParam("user") String user, String password) {
if ("test".equals(user) && "test".equals(password)) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(this.secretKey);
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
JwtBuilder builder = Jwts.builder().setIssuedAt(now).setSubject("test")
.signWith(signatureAlgorithm, signingKey);
return builder.compact();
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
Und die HelloResource
Echos nur den Benutzer zurück:
@GET
@RolesAllowed({"ANY"})
public String hello(@Auth User user) {
return "hello user \"" + user.getName() + "\"";
}
JWTCredentialAuthFilter
liefert Berechtigungsnachweise für beide Authentifizierungsschemata:
@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;
}
}
JWTAuthenticator
ist, wenn JWT Anmeldeinformationen bereitgestellt:
public class JWTAuthenticator implements Authenticator<JWTCredentials, User> {
private String secret;
public JWTAuthenticator(String jwtsecret) {
this.secret = jwtsecret;
}
@Override
public Optional<User> authenticate(JWTCredentials credentials) throws AuthenticationException {
try {
Claims claims = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(this.secret))
.parseClaimsJws(credentials.getJwtToken()).getBody();
User user = new User();
user.setName(claims.getSubject());
return Optional.ofNullable(user);
} catch (@SuppressWarnings("unused") ExpiredJwtException | UnsupportedJwtException
| MalformedJwtException | SignatureException | IllegalArgumentException e) {
return Optional.empty();
}
}
}
JWTDefaultAuthenticator
ist, wenn keine Anmeldeinformationen vorhanden sind, wird der Code ein leeres Benutzer geben:
public class JWTDefaultAuthenticator implements Authenticator<JWTCredentials, User> {
@Override
public Optional<User> authenticate(JWTCredentials credentials) throws AuthenticationException {
return Optional.of(new User());
}
}
UserAuthorizer
erlaubt die "ANY" Rolle, solange der Benutzer nicht null ist:
public class UserAuthorizer implements Authorizer<User> {
@Override
public boolean authorize(User user, String role) {
return user != null && "ANY".equals(role)
}
}
Wenn alles gut geht,
curl -s -X POST -d 'test' http://localhost:8080/token/test
geben Ihnen so etwas wie:
eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDk3MDYwMjYsInN1YiI6InRlc3QifQ.ZrRmWTUDpaA6JlU4ysIcFllxtqvUS2OPbCMJgyou_tY
und diese Abfrage
curl -s -X POST -d 'xtest' http://localhost:8080/token/test
wird scheitern mit
{"code":401,"message":"HTTP 401 Unauthorized"}
(BTW, "test" in der URL der Namen Benutzer und "test" in den Post-Daten ist das Passwort. So einfach wie Grund Auth und kann für CORS konfiguriert werden.)
und die Anfrage
curl -s -X GET -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1MDk3MDYwMjYsInN1YiI6InRlc3QifQ.ZrRmWTUDpaA6JlU4ysIcFllxtqvUS2OPbCMJgyou_tY' http://localhost:8080/hello
hello user "test"
während
curl -s -X GET -H 'Authorization: Bearer invalid' http://localhost:8080/hello
und
curl -s -X GET http://localhost:8080/hello
zeigen
wird in
{"code":403,"message":"User not authorized."}
Danke, aber diese Bibliothek ist nicht stabil, es ist nur Version 0.9.0 :( – kaleeway
Zwei Dinge: Lassen Sie sich von der Version nicht irreführen, ich weiß, dass Dropwizard für viele verschiedene Produktionsumgebungen vor Version 1 verwendet wurde. Zweitens verwendet die Dropwizard JWT-Bibliothek die gleiche Bibliothek. Überprüfen Sie die pom.xml davon. –
Danke, ich habe deine Lösung ausprobiert, aber es sagt, dass es die 'JWTCredentials' Klasse nicht finden kann, muss ich das machen oder wird es von einer anderen Bibliothek bereitgestellt? – kaleeway