如何validationJersey中的用户

我正在使用Jersey在Java中编写RESTful应用程序,我需要对用户进行身份validation。 我知道我可以使用注释@RolesAllowed在资源中指定角色,但我无法理解用户如何与特定角色相关联。 客户端以这种方式发送用户名和密码

HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(user, password); Client client = ClientBuilder.newClient(); client.register(feature); WebTarget target = client.target(baseUrl).path(urlString); Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON); Response response = invocationBuilder.get(); 

假设某些方法只能由超级用户和其他用户使用,当客户端发送用户名和密码时,如何区分它们?

我知道我可以使用注释@RolesAllowed在资源中指定角色,但我无法理解用户如何与特定角色相关联

角色信息存储在DB中。 假设您有一个User对数据库中的USER和ROLES表进行建模

 class User { String username; List roles; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public List getRoles() { return roles; } public void setRoles(List roles) { this.roles = roles; } } 

你可以在泽西filter中找到User 。 这也是您要进行身份validation的地方。

 @Provider @Priority(Priorities.AUTHENTICATION) // needs to happen before authorization class AuthenticationFilter implements ContainerRequestFilter { @Inject private UserService userService; // this is your own service @Override public void filter(ContainerRequestFilter filter) { // note, this is a lazy implementation of Basic auth. // it doesn't do ant error checking. Please see // link at bottom for better imlementation String authzHeader = filter.getHeaderString(HttpHeaders.AUTHORIZATION); // (1) String decoded = Base64.decodeAsString(authzHeader); String[] split = decoded.split(":"); User user = userService.getUser(split[0]); // (2) if (user == null || !user.getPassword().equals(someHash(split[1])) { // (3) throw new UnauthorizedException(); } SecurityContext oldContext = filter.getSecurityContext(); // (4) filter.setSecurityContext(new BasicSecurityConext(user, oldContext.isSecure())); } } 

你在这做的是:

  1. 解析Basic Auth Authorization标头
  2. 使用User名获取用户
  3. 进行身份validation
  4. 设置新的SecurityContext

BasicSecurityContext如下所示。 您可以在此处将角色与用户关联。

 static class BasicSecurityContext implements SecurityContext { private final User user; private final boolean secure; public BasicSecurityContext(User user, boolean secure) { this.user = user; this.secure = secure; } @Override public Principal getUserPrincipal() { return new Principal() { @Override public String getName() { return user.getUsername(); } }; } @Override public String getAuthenticationScheme() { return SecurityContext.BASIC_AUTH; } @Override public boolean isSecure() { return secure; } @Override public boolean isUserInRole(String role) { return user.getRoles().contains(role); } } 

如果你看一下isUserInRole的底部。 会发生什么是Jersey将从资源方法或类中获取@RolesAllowed注释,获取值,然后将它们传递给isUserInRole 。 如果返回true ,则授权用户。 在伪代码中

 @RolesAllowed({"USER", "SUPER_USER"}) public Response get() {} ... RolesAllowed annotation = resourceMethod.getAnnotation(RolesAllowed.class); String roles = annotation.value(); SecurityContext context = getSecurityContext(); for (String role: roles) { if (context.isUserInRole(role)) { return; } } throw new ForbiddenException(); 

这只是伪代码,但它显示了Jersey如何使用@RolesAllowedSecurityContext以及如何实现isUserInRole来处理授权。

此授权function不会自动打开。 你需要自己打开它。 为此,只需注册RolesAllowedDynamicFeature

 public JerseyConfig extends ResourceConfig { public JerseyConfig() { register(RolesAllowedDynamicFeature.class); } } 

这里要注意的一点是,在上述所有内容中,我们正在实现基本身份validation和安全上下文的设置。 这没有什么不妥。 但是如果你使用servlet容器认证机制,Jersey实际上将从HttpServletRequest获取auth信息。 HttpServletRequest有一个getUserPrincipal()方法和一个isUserInRole方法。 Jersey将使用这些来委托SecurityContext 。 因此,如果您用户容器身份validation,那么您实际上并不需要实现任何东西。 您只需注册RolesAllowedDynamicFeature

如果要使用容器的身份validation机制,则应查阅服务器的文档。 在使用服务器设置域之后,您将需要使用安全信息配置web.xml 。 下面的链接中有一个例子。 您还应该在Web安全性部分下的Java EE文档中找到此信息。

也可以看看:

  • filter和拦截器,以了解有关使用filter的更多信息。
  • 有关在泽西岛使用安全性的更多信息的安全性。
  • 更好地实现基本的authfilter

我们需要解决两件事

  1. 身份validation – 检查用户是否真的是它声称的用户
  2. 授权 – 如果经过身份validation的用户有权访问给定方法

要同时执行身份validation和授权,我们需要一个存储的数据存储,它存储以下映射:

  1. 用户与其密码之间的映射
  2. 角色和用户之间的映射
  3. 角色和权限之间的映射

这里需要第一个映射进行身份validation,其他两个映射用于授权。

另请注意,我们需要为每个API调用执行身份validation和授权。 所以我们将进行大量的读操作。

因此,通常使用目录服务器或诸如Apache DS的Ldap服务器来存储这些映射,因为目录服务器是读取优化的数据存储。

在RESTful应用程序中,通常使用filter从请求标头中提取用户名和密码,并使用Ldap服务器进行身份validation。 如果validation成功,则下一步是通过查询用户角色和角色权限映射从Ldap服务器提取用户的权限。 如果用户已获得授权,则仅在该情况下,控件将流向实际的API业务逻辑。

有关详细信息,请参阅此答案。

HttpAuthenticationFeature类提供HttpBasic和Digest客户端身份validationfunction。 该function以4种模式之一工作;

BASIC:它是抢占式身份validation方式,即始终随每个HTTP请求发送信息。 此模式必须与SSL / TLS的使用相结合,因为密码仅发送BASE64编码。

BASIC NON-PREEMPTIVE:非抢占式身份validation方式,即仅当服务器拒绝具有401状态代码的请求时才添加身份validation信息,然后使用身份validation信息重复请求。

DIGEST: Http摘要认证。 不需要使用SSL / TLS。

通用:在非抢占模式下组合基本身份validation和摘要身份validation,即在401响应的情况下,根据WWW-Authenticate HTTP头中定义的请求身份validation使用适当的身份validation。

要使用HttpAuthenticationFeature,请构建它的实例并向客户端注册。 例如;

1)基本认证模式

 HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic("username", "password"); final Client client = ClientBuilder.newClient(); client.register(feature); 

2)基本认证:非prempitive模式

 HttpAuthenticationFeature feature = HttpAuthenticationFeature.basicBuilder() .nonPreemptive() .credentials("username", "password") .build(); final Client client = ClientBuilder.newClient(); client.register(feature); 

3)通用模式

 //Universal builder having different credentials for different schemes HttpAuthenticationFeature feature = HttpAuthenticationFeature.universalBuilder() .credentialsForBasic("username1", "password1") .credentials("username2", "password2").build(); final Client client = ClientBuilder.newClient(); client.register(feature);