IAm*_*aja 21 java jax-rs jersey basic-authentication dropwizard
我试图了解DropWizard中的身份验证和授权是如何工作的.我已经阅读了他们的auth指南以及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"));
}
}
Run Code Online (Sandbox Code Playgroud)
然后在我的Application
子类中:
@Override
public void run(BackendConfiguration configuration, Environment environment) throws Exception {
environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(new SimpleAuthenticator(), "SUPER SECRET STUFF"));
}
Run Code Online (Sandbox Code Playgroud)
然后在资源方法中:
@GET
@Path("address/{address_id}")
@Override
public Address getAddress(@Auth @PathParam("address_id") Long id) {
addressDao.getAddressById(id);
}
Run Code Online (Sandbox Code Playgroud)
我认为我已经为基本身份验证正确配置了这个半配置,但是没有理解该角色SimpleCredential
和SimplePrincipal
播放.特别:
SimpleCredential
,并SimplePrincipal
与基本身份验证玩?我是否需要向他们或其他类添加任何内容以进行基本身份验证工作,以便唯一有效的用户名是simple_user
唯一有效的密码12345
?SimplePrincipal
?或者是Web服务不存在授权的概念?Pau*_*tha 36
基本身份验证协议规定客户端请求应具有表头形式的标头
Authorization: Basic Base64Encoded(username:password)
Run Code Online (Sandbox Code Playgroud)
其中Base64Encoded(username:password)
是一个实际的Base64编码字符串username:password
.例如,如果我的用户名和密码是peeskillet:pass
,则应将标题发送为
Authorization: Basic cGVlc2tpbGxldDpwYXNz
Run Code Online (Sandbox Code Playgroud)
话虽这么说,泽西岛客户端(假设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);
Run Code Online (Sandbox Code Playgroud)
这就是我们需要使用授权标头进行简单的GET请求.
SimpleCredential:对于Basic auth,我们实际上需要使用BasicCredentials
而不是我们自己的凭据.基本上,请求将通过BasicAuthProvider
.提供程序将解析Authorization标头并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);
}
}
Run Code Online (Sandbox Code Playgroud)
我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";
}
Run Code Online (Sandbox Code Playgroud)
有些人可能更喜欢使用额外的过滤层进行授权,但是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();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,使用此配置将所有内容组合在一起
environment.jersey().register(new BasicAuthProvider<SimplePrincipal>(
new SimpleAuthenticator(),
"Basic Example Realm")
);
Run Code Online (Sandbox Code Playgroud)
以及我之前发布的客户凭据,当我们发出请求时,我们应该返回一个
{"Hello": "peeskillet"}
Run Code Online (Sandbox Code Playgroud)
另外应该提到单独的基本身份验证不安全,建议通过SSL完成
见相关:
几件事:
对于Dropwizard 0.8.x,Basic Auth的配置有所改变.你可以在这里看到更多.一个简单的例子就是
SimpleAuthenticator auth = new SimpleAuthenticator();
env.jersey().register(AuthFactory.binder(
new BasicAuthFactory<>(auth,"Example Realm",SimplePrincipal.class)));
Run Code Online (Sandbox Code Playgroud)请参阅上面的链接以了解推荐用法 AuthenticationException