我有一个JAX-RS服务,我希望所有用户都能访问我的服务,但只有那些有权查看结果的用户。基于角色的安全性和现有的REALMS和身份验证方法并不符合我的要求。
例如:
问题是:我应该在哪里检查用户ID,在某个单独的过滤器,安全上下文或每个REST方法实现中?如何使用此ID提供REST方法,可以在按ID过滤请求后在每个方法中注入securityContext吗?
我正在使用GlassFish 4.1和Jersey JAX-RS实现。
答案 0 :(得分:24)
您可以在ContainerRequestFilter
中执行此逻辑。在这里处理自定义安全功能非常常见。
需要考虑的一些事项
该类应使用@Priority(Priorities.AUTHENTICATION)
进行注释,以便在其他过滤器(如果有)之前执行。
您应该使用过滤器内的SecurityContext
。我所做的是实现SecurityContext
。无论如何你都可以真正实现它。
这是一个没有任何安全逻辑
的简单示例@Provider
@Priority(Priorities.AUTHENTICATION)
public class SecurityFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
SecurityContext originalContext = requestContext.getSecurityContext();
Set<String> roles = new HashSet<>();
roles.add("ADMIN");
Authorizer authorizer = new Authorizer(roles, "admin",
originalContext.isSecure());
requestContext.setSecurityContext(authorizer);
}
public static class Authorizer implements SecurityContext {
Set<String> roles;
String username;
boolean isSecure;
public Authorizer(Set<String> roles, final String username,
boolean isSecure) {
this.roles = roles;
this.username = username;
this.isSecure = isSecure;
}
@Override
public Principal getUserPrincipal() {
return new User(username);
}
@Override
public boolean isUserInRole(String role) {
return roles.contains(role);
}
@Override
public boolean isSecure() {
return isSecure;
}
@Override
public String getAuthenticationScheme() {
return "Your Scheme";
}
}
public static class User implements Principal {
String name;
public User(String name) {
this.name = name;
}
@Override
public String getName() { return name; }
}
}
要注意的一些事项
SecurityContext
isUserInRole
方法。这将用于授权。User
类,它实现了java.security.Principal
。我退回了这个自定义对象SecurityContext
ContainerRequestContext
现在怎样?让我们看一个简单的资源类
@Path("secure")
public class SecuredResource {
@GET
@RolesAllowed({"ADMIN"})
public String getUsername(@Context SecurityContext securityContext) {
User user = (User)securityContext.getUserPrincipal();
return user.getName();
}
}
需要注意的一些事项:
SecurityContext
被注入到方法中。 Principal
并将其投放到User
。所以你真的可以创建任何实现Principal
的类,并根据需要使用这个对象。使用@RolesAllowed
注释。对于Jersey,有一个过滤器通过传入SecurityContext.isUserInRole
注释中的每个值来检查@RolesAllowed
,以查看是否允许用户访问该资源。
要在Jersey上启用此功能,我们需要注册RolesAllowedDynamicFeature
@ApplicationPath("/api")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("packages.to.scan");
register(RolesAllowedDynamicFeature.class);
}
}
答案 1 :(得分:1)
我正在寻找一种独立于泽西岛的解决方案,适用于Wildfly - &gt;发现了这个github示例实现:
https://github.com/sixturtle/examples/tree/master/jaxrs-jwt-filter
它应该给你一个如何解决它的提示。
实现一个实现ContainerRequestFilter的JWTRequestFilter https://github.com/sixturtle/examples/blob/master/jaxrs-jwt-filter/src/main/java/com/sixturtle/jwt/JWTRequestFilter.java
如上所述,并在web.xml中将过滤器注册为resteasy提供程序:
<context-param>
<description>Custom JAX-RS Providers</description>
<param-name>resteasy.providers</param-name>
<param-value>com.sixturtle.jwt.JWTRequestFilter</param-value>
</context-param>
<context-param>
<param-name>resteasy.role.based.security</param-name>
<param-value>true</param-value>
</context-param>