Ответ 1
Вопрос 1:
Базовая аутентификация утверждает, что запрос клиента должен иметь заголовок в форме
Authorization: Basic Base64Encoded(username:password)
где Base64Encoded(username:password)
- фактическая строка с кодировкой Base64 username:password
. Например, если мое имя пользователя и пароль peeskillet:pass
, заголовок должен быть отправлен как
Authorization: Basic cGVlc2tpbGxldDpwYXNz
При этом клиент Джерси (предположительно 1.x) имеет HTTPBasicAuthFilter
, который является фильтром на стороне клиента, который будет обрабатывать часть кодирования для нас. Таким образом, запрос на стороне клиента может выглядеть примерно так:
Client client = Client.create();
WebResource resource = client.resource(BASE_URI);
client.addFilter(new HTTPBasicAuthFilter("peeskillet", "pass"));
String response = resource.get(String.class);
Это все, что нам нужно будет сделать простым запросом GET с заголовком авторизации.
Вопрос 2:
SimpleCredential: Для Basic auth нам действительно потребуется использовать BasicCredentials
вместо наших собственных учетных данных. В принципе, запрос будет проходить через BasicAuthProvider
. Поставщик будет анализировать заголовок авторизации и создать объект BasicCredentials
из проанализированного имени пользователя и пароля. Как только эта обработка завершится, BasicCredentials
будет передана нашим SimpleAuthenticator
. Мы используем эти учетные данные для аутентификации пользователя.
SimplePrincipal: - это в основном то, что мы будем использовать для авторизации клиента. Из процесса аутентификации мы можем построить принципал, который будет использоваться для авторизации позже (см. Вопрос 3). Таким образом, пример может выглядеть примерно как
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
и создал простой класс Roles
.
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";
}
Вопрос 3:
Некоторые могут предпочесть наличие дополнительного фильтра для авторизации, но Dropwizard, похоже, придерживается мнения, что авторизация должна выполняться в классе ресурсов (я забыл, где именно я его прочитал, но я считаю, что их аргумент является тестируемостью). Что происходит с SimplePrincial
, который мы создали в SimpleAuthenticator
, состоит в том, что он может быть введен в наш ресурсный метод с использованием аннотаций @Auth
. Мы можем использовать SimplePrincipal
для авторизации. Что-то вроде
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();
}
}
Итак, все вместе, с этой конфигурацией
environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(
new SimpleAuthenticator(),
"Basic Example Realm")
);
и учетные данные клиента, которые я опубликовал ранее, когда мы делаем запрос, мы должны получить возвращенный
{"Hello": "peeskillet"}
Также следует упомянуть, что Basic auth не является безопасным, и рекомендуется делать это через SSL
См. раздел Связанный:
UPDATE
Несколько вещей:
-
Для Dropwizard 0.8.x конфигурация Basic Auth немного изменилась. Вы можете видеть здесь. Простым примером может быть
SimpleAuthenticator auth = new SimpleAuthenticator(); env.jersey().register(AuthFactory.binder( new BasicAuthFactory<>(auth,"Example Realm",SimplePrincipal.class)));
-
См. ссылку выше для рекомендуемого использования
AuthenticationException