java - example - rest token authentication
DropWizard Auth por ejemplo (1)
Pregunta 1:
El protocolo de autenticación básico indica que la solicitud del cliente debe tener un encabezado en forma de
Authorization: Basic Base64Encoded(username:password)
donde Base64Encoded(username:password)
es una cadena codificada en Base64 real del username:password
de username:password
. Por ejemplo, si mi nombre de usuario y contraseña son peeskillet:pass
, el encabezado debe enviarse como
Authorization: Basic cGVlc2tpbGxldDpwYXNz
Dicho esto, el cliente de Jersey (suponiendo que 1.x) tiene un HTTPBasicAuthFilter
, que es un filtro del lado del cliente, que manejará la parte de codificación para nosotros. Así que la solicitud del lado del cliente podría verse algo así como
Client client = Client.create();
WebResource resource = client.resource(BASE_URI);
client.addFilter(new HTTPBasicAuthFilter("peeskillet", "pass"));
String response = resource.get(String.class);
Eso es todo lo que necesitaríamos para realizar una solicitud GET simple con el encabezado de autorización.
Pregunta 2:
SimpleCredential: para la autenticación básica, en realidad BasicCredentials
usar BasicCredentials
, en lugar de nuestras propias credenciales. Básicamente, la solicitud pasará por el BasicAuthProvider
. El proveedor analizará el encabezado de Autorización y creará un objeto BasicCredentials
partir del nombre de usuario y la contraseña analizados. Una vez que el procesamiento haya finalizado, las BasicCredentials
pasarán a nuestro SimpleAuthenticator
''s. Usamos esas credenciales para autenticar al usuario.
SimplePrincipal: es básicamente lo que usaremos para autorizar al cliente. Desde el proceso de autenticación, podemos crear un principal, que se usará para autorizar más adelante (consulte la pregunta 3). Así que un ejemplo podría parecer algo como
import com.google.common.base.Optional;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
public class SimpleAuthenticator implements Authenticator<BasicCredentials,
SimplePrincipal> {
@Override
public Optional<SimplePrincipal> authenticate(BasicCredentials credentials)
throws AuthenticationException {
// Note: this is horrible authentication. Normally we''d use some
// service to identify the password from the user name.
if (!"pass".equals(credentials.getPassword())) {
throw new AuthenticationException("Boo Hooo!");
}
// from some user service get the roles for this user
// I am explicitly setting it just for simplicity
SimplePrincipal prince = new SimplePrincipal(credentials.getUsername());
prince.getRoles().add(Roles.ADMIN);
return Optional.fromNullable(prince);
}
}
SimplePrincipal
un poco la clase SimplePrincipal
y creé una clase de Roles
simple.
public class SimplePrincipal {
private String username;
private List<String> roles = new ArrayList<>();
public SimplePrincipal(String username) {
this.username = username;
}
public List<String> getRoles() {
return roles;
}
public boolean isUserInRole(String roleToCheck) {
return roles.contains(roleToCheck);
}
public String getUsername() {
return username;
}
}
public class Roles {
public static final String USER = "USER";
public static final String ADMIN = "ADMIN";
public static final String EMPLOYEE = "EMPLOYEE";
}
Pregunta 3:
Algunos pueden preferir tener una capa de filtro adicional para la autorización, pero Dropwizard parece tener la opinión de que la autorización debe ocurrir en la clase de recurso (olvidé exactamente dónde lo leí, pero creo que su argumento es verificable). Lo que sucede con el SimplePrincial
que creamos en SimpleAuthenticator
es que se puede inyectar en nuestro método de recursos, con el uso de las anotaciones de @Auth
. Podemos usar el SimplePrincipal
para autorizar. Algo como
import dropwizard.sample.helloworld.security.Roles;
import dropwizard.sample.helloworld.security.SimplePrincipal;
import io.dropwizard.auth.Auth;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/simple")
public class SimpleResource {
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getResponse(@Auth SimplePrincipal principal) {
if (!principal.isUserInRole(Roles.ADMIN)) {
throw new WebApplicationException(Response.Status.FORBIDDEN);
}
return Response.ok(
"{/"Hello/": /"" + principal.getUsername() + "/"}").build();
}
}
Así que poniéndolo todo junto, con esta configuración.
environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(
new SimpleAuthenticator(),
"Basic Example Realm")
);
y las credenciales del cliente que publiqué anteriormente, cuando hacemos la solicitud, debemos obtener un
{"Hello": "peeskillet"}
También se debe mencionar que la autenticación básica por sí sola no es segura, y se recomienda realizarla sobre SSL
Ver Relacionados:
- DropWizard Auth Realms
- SSL con DropWizard
ACTUALIZAR
Un par de cosas:
Para Dropwizard 0.8.x, la configuración de Autenticación básica ha cambiado un poco. Puedes ver más aquí . Un ejemplo simple sería
SimpleAuthenticator auth = new SimpleAuthenticator(); env.jersey().register(AuthFactory.binder( new BasicAuthFactory<>(auth,"Example Realm",SimplePrincipal.class)));
Vea el enlace anterior para el uso recomendado de
AuthenticationException
Estoy tratando de entender cómo funcionan la autenticación y la autorización en DropWizard . He leído su guía de autenticación y el dropwizard-security en GitHub, pero siento que todavía me faltan algunos conceptos importantes.
public class SimpleCredential {
private String password;
public SimpleCredential(String password) {
super();
this.password = password;
}
}
public class SimplePrincipal {
pivate String username;
public SimplePrincipal(String username) {
super();
this.username = username;
}
}
public class SimpleAuthenticator implements Authenticator<SimpleCredential, SimplePrincipal> {
@Override
public Optional<SimplePrincipal> authenticate(SimpleCredential credential) throws AuthenticationException {
if(!"12345".equals(credential.getPassword())) {
throw new AuthenticationException("Sign in failed.");
}
Optional.fromNullable(new SimplePrincipal("simple_user"));
}
}
Y luego en mi subclase de Application
:
@Override
public void run(BackendConfiguration configuration, Environment environment) throws Exception {
environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(new SimpleAuthenticator(), "SUPER SECRET STUFF"));
}
Y luego en un método de recursos:
@GET
@Path("address/{address_id}")
@Override
public Address getAddress(@Auth @PathParam("address_id") Long id) {
addressDao.getAddressById(id);
}
Creo que lo tengo medio configurado correctamente para la autenticación básica, pero no entiendo el rol que desempeñan SimpleCredential
y SimplePrincipal
. Específicamente:
- ¿Cómo establezco un nombre de usuario / contraseña de autenticación básica desde el cliente de Jersey / JAX-RS?
- ¿Qué papel desempeñan
SimpleCredential
ySimplePrincipal
con la autenticación básica? ¿Debo agregar algo a ellos u otras clases para hacer que la autenticación básica funcione de manera que el único nombre de usuario válido seasimple_user
y la única contraseña válida sea12345
? - ¿Cómo hago cumplir el acceso / autenticación / roles a través de
SimplePrincipal
? ¿O es que el concepto de autorización no existe con los servicios web?