我知道我可以使用注释 @RolesAllowed 指定资源中的角色,但我无法理解用户是如何与特定角色相关联的
角色信息存储在数据库中。假设你有一个 User 来模拟数据库中的 USER 和 ROLES 表
class User {
String username;
List<String> roles;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public List<String> getRoles() { return roles; }
public void setRoles(List<String> roles) { this.roles = roles; }
}
您会在 Jersey 过滤器中获得 User。这也是您进行身份验证的地方。
@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(ContainerRequestContex context) {
// 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 = context.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 = context.getSecurityContext(); // (4)
context.setSecurityContext(new BasicSecurityConext(user, oldContext.isSecure()));
}
}
你在这里做的是:
- 解析基本认证授权标头
- 使用用户名获取
User
- 进行身份验证
- 设置一个新的
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,则用户被授权。在伪代码中
@GET
@Path("/somepath")
@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 如何使用@RolesAllowed、SecurityContext 处理授权,以及如何实现isUserInRole。
此授权功能不会自动开启。你需要自己打开它。为此,只需注册RolesAllowedDynamicFeature
public JerseyConfig extends ResourceConfig {
public JerseyConfig() {
register(RolesAllowedDynamicFeature.class);
}
}
这里要注意的一点是,在上述所有内容中,我们正在实现我们的基本身份验证和安全上下文的设置。这并没有什么问题。但是如果你使用 servlet 容器身份验证机制,Jersey 实际上会从HttpServletRequest 获取身份验证信息。 HttpServletRequest 有一个 getUserPrincipal() 方法和一个 isUserInRole 方法。泽西岛将使用这些来委托SecurityContext。因此,如果您是用户容器身份验证,那么您实际上不需要实现任何东西。您只需注册RolesAllowedDynamicFeature
如果您想使用容器的身份验证机制,您应该查阅服务器的文档。在您的服务器中设置领域后,您需要使用安全信息配置web.xml。下面的链接中有一个示例。您还应该在 Web 安全部分下的 Java EE 文档中找到此信息。
另请参阅: