DropWizard Auth通过示例 [英] DropWizard Auth by Example

查看:96
本文介绍了DropWizard Auth通过示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解 DropWizard 中的身份验证和授权的工作方式.我已经阅读了他们的身份验证指南

I'm trying to understand how authentication and authorization work in DropWizard. I've read their auth guide as well as the dropwizard-security project on GitHub, but feel like I'm still missing a few important concepts.

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"));
    }
}

然后在我的Application子类中:

@Override
public void run(BackendConfiguration configuration, Environment environment) throws Exception {
    environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(new SimpleAuthenticator(), "SUPER SECRET STUFF"));
}

然后在资源方法中:

@GET
@Path("address/{address_id}")
@Override
public Address getAddress(@Auth @PathParam("address_id") Long id) {
    addressDao.getAddressById(id);
}

我认为我已经正确配置了一半用于基本身份验证,但不了解SimpleCredentialSimplePrincipal所扮演的角色.具体来说:

I think I have this half-configured correctly for basic auth, but not understanding the role that SimpleCredential and SimplePrincipal play. Specifically:

  1. 如何从Jersey/JAX-RS客户端设置基本身份验证用户名/密码?
  2. SimpleCredentialSimplePrincipal在基本身份验证中扮演什么角色?我是否需要向它们或其他类添加任何内容以使基本身份验证工作,以便唯一有效的用户名是simple_user而唯一有效的密码是12345?
  3. 如何通过SimplePrincipal强制执行访问/授权/角色?还是Web服务不存在授权的概念?
  1. How do I set basic auth username/password from the Jersey/JAX-RS client?
  2. What role do SimpleCredential and SimplePrincipal 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 is simple_user and the only valid password is 12345?
  3. How do I enforce access/authroization/roles via SimplePrincipal? Or is the concept of authorization non-existent with web services?

推荐答案

问题1:

基本身份验证协议规定,客户端请求的标头应为

Question 1:

Basic Authentication protocol states the client request should have a header in the form of

Authorization: Basic Base64Encoded(username:password)

其中,Base64Encoded(username:password)username:password的实际Base64编码的字符串.例如,如果我的用户名和密码为peeskillet:pass,则标头应作为

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

Authorization: Basic cGVlc2tpbGxldDpwYXNz

话虽这么说,Jersey Client(假设1.x)有一个HTTPBasicAuthFilter,它是一个客户端过滤器,它将为我们处理编码部分.因此,客户端请求可能看起来像

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

Client client = Client.create();
WebResource resource = client.resource(BASE_URI);
client.addFilter(new HTTPBasicAuthFilter("peeskillet", "pass"));
String response = resource.get(String.class);

这就是我们要做的,带有授权标头的简单GET请求.

That's all we would need to make a simple GET request with the authorization header.

SimpleCredential::对于基本身份验证,实际上我们将被要求使用BasicCredentials而不是我们自己的凭据.基本上,请求将通过BasicAuthProvider.提供者将解析Authorization标头,并从解析的用户名和密码创建BasicCredentials对象.处理完成后,BasicCredentials将传递给我们的SimpleAuthenticator.我们使用这些凭据对用户进行身份验证.

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.

SimplePrincipal:基本上就是我们用来授权客户端的对象.从身份验证过程中,我们可以构建一个主体,该主体将在以后用于授权(请参阅问题3).因此,一个例子可能看起来像

SimplePrincipal: is basically what we will use to authorize the 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

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类.

I altered the SimplePrincipal class a bit, and created a simple Roles class.

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似乎认为授权应该在资源类中进行(我忘记了阅读的确切位置,但我相信了 他们的论据是可测试性).我们在SimpleAuthenticator中创建的SimplePrincial发生的事情是,可以使用@Auth批注将其注入到我们的资源方法中.我们可以使用SimplePrincipal进行授权.像

Question 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 believe their 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

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"}


还应该指出,仅基本身份验证是不安全的,建议通过SSL进行


Also it should be mentioned that Basic auth alone is not secure, and it is recommended to be done over SSL

查看相关内容:

  • DropWizard Auth Realms
  • SSL with DropWizard

几件事:

  • 对于Dropwizard 0.8.x,基本身份验证的配置有所更改.您可以在>在此处获得更多 .一个简单的例子是

  • 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)));

  • 有关推荐使用AuthenticationException

    这篇关于DropWizard Auth通过示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆