java DropWizard 身份验证示例
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27392224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DropWizard Auth by Example
提问by IAmYourFaja
I'm trying to understand how authentication and authorization work in DropWizard. I've read their auth guideas well as the dropwizard-securityproject on GitHub, but feel like I'm still missing a few important concepts.
我试图了解身份验证和授权在DropWizard 中是如何工作的。我已经阅读了他们的身份验证指南以及GitHub 上的dropwizard-security项目,但感觉我仍然缺少一些重要的概念。
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"));
}
}
And then in my Application
subclass:
然后在我的Application
子类中:
@Override
public void run(BackendConfiguration configuration, Environment environment) throws Exception {
environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(new SimpleAuthenticator(), "SUPER SECRET STUFF"));
}
And then in a resource method:
然后在资源方法中:
@GET
@Path("address/{address_id}")
@Override
public Address getAddress(@Auth @PathParam("address_id") Long id) {
addressDao.getAddressById(id);
}
I think I have this half-configured correctly for basic auth, but not understanding the role that SimpleCredential
and SimplePrincipal
play. Specifically:
我觉得我有这个半正确配置为基本身份验证,但不理解的角色SimpleCredential
和SimplePrincipal
发挥。具体来说:
- How do I set basic auth username/password from the Jersey/JAX-RS client?
- What role do
SimpleCredential
andSimplePrincipal
play with basic auth? Do I need to add anything to them or other classes to make basic auth work such that the only valid username issimple_user
and the only valid password is12345
? - How do I enforce access/authroization/roles via
SimplePrincipal
? Or is the concept of authorization non-existent with web services?
- 如何从 Jersey/JAX-RS 客户端设置基本身份验证用户名/密码?
- 什么作用
SimpleCredential
,并SimplePrincipal
与基本身份验证戏?我是否需要向它们或其他类添加任何内容以使基本身份验证工作,以便唯一有效的用户名simple_user
和唯一有效的密码是12345
? - 我如何通过 强制访问/授权/角色
SimplePrincipal
?或者 Web 服务不存在授权的概念?
回答by Paul Samsotha
Question 1:
问题 1:
Basic Authenticationprotocol states the client request should have a header in the form of
基本身份验证协议规定客户端请求应具有以下形式的标头
Authorization: Basic Base64Encoded(username:password)
where Base64Encoded(username:password)
is an actual Base64 encoded string of the username:password
. For example, if my username and password are peeskillet:pass
, the header should be sent out as
其中Base64Encoded(username:password)
是 的实际 Base64 编码字符串username:password
。例如,如果我的用户名和密码是peeskillet:pass
,则标头应作为
Authorization: Basic cGVlc2tpbGxldDpwYXNz
That being said, the Jersey Client (assuming 1.x) has an HTTPBasicAuthFilter
, which is a client side filter, that will handle the encoding part for us. So the client side request might look something like
话虽如此,Jersey 客户端(假设是 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);
That's all we would need to make a simple GET request with the authorization header.
这就是我们使用授权标头发出简单 GET 请求所需的全部内容。
Question 2:
问题2:
SimpleCredential:For Basic auth, we would actually be required to use BasicCredentials
, instead of our own credentials. Basically, the request will go through the BasicAuthProvider
. The provider will parse the Authorization header and create a BasicCredentials
object from the parsed username and password. Once that processing has finished, the BasicCredentials
will get passed to our SimpleAuthenticator
's. We use those credentials to authenticate the user.
SimpleCredential:对于基本身份验证,我们实际上需要使用BasicCredentials
,而不是我们自己的凭据。基本上,请求将通过BasicAuthProvider
. 提供者将解析 Authorization 标头并BasicCredentials
根据解析的用户名和密码创建一个对象。处理完成后,BasicCredentials
将传递给我们SimpleAuthenticator
的 。我们使用这些凭据对用户进行身份验证。
SimplePrincipal:is basically what we will use to authorizethe client. From the authentication process, we can build a principal, that will be used to authorize later (see Question 3). So an example might look something like
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);
}
}
I altered the SimplePrincipal
class a bit, and created a simple Roles
class.
我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";
}
Question 3:
问题 3:
Some might prefer to have an extra filter layer for authorization, but Dropwizard appears to have the opinionated view that the authorization should occur in the resource class (I forgot exactly where I read it, but I believetheir argument is testability). What happens with the SimplePrincial
that we created in the SimpleAuthenticator
is that it can be injected into our resource method, with the use of the @Auth
annotations. We can use the SimplePrincipal
to authorize. Something like
有些人可能更喜欢有一个额外的授权过滤层,但 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();
}
}
So putting it all together, with this configuration
所以把它放在一起,用这个配置
environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(
new SimpleAuthenticator(),
"Basic Example Realm")
);
and the client credentials I posted previously, when we make the request, we should get a returned
以及我之前发布的客户端凭据,当我们发出请求时,我们应该得到一个返回
{"Hello": "peeskillet"}
Also it should be mentioned that Basic auth alone is not secure, and it is recommended to be done over SSL
还应该提到的是,单独的 Basic auth 并不安全,建议通过 SSL 完成
See Related:
见相关:
UPDATE
更新
A couple things:
一些事情:
For Dropwizard 0.8.x, the configuration of Basic Auth has changed a bit. You can see more here. A simple example would be
SimpleAuthenticator auth = new SimpleAuthenticator(); env.jersey().register(AuthFactory.binder( new BasicAuthFactory<>(auth,"Example Realm",SimplePrincipal.class)));
See above link for recommended usage of
AuthenticationException