[英]Custom JAX-RS authorization - using JWT in each request
I have a JAX-RS service where I want all my users to access my services, but just those who have rights to see the result. 我有一个JAX-RS服务,我希望所有用户都能访问我的服务,但只有那些有权查看结果的用户。 Roles based security and existing REALMS and atuhentication methods doesn't fit my requirement.
基于角色的安全性和现有的REALMS和身份验证方法不符合我的要求。
For example: 例如:
Question is: Where should I check for users ID, in some separate filter, security context or in every REST method implementation? 问题是:我应该在哪里检查用户ID,在一些单独的过滤器,安全上下文或每个REST方法实现中? How to provide REST methods with this ID, can securityContext be injected in every method after filtering request by ID?
如何使用此ID提供REST方法,在按ID过滤请求后,是否可以在每个方法中注入securityContext?
I'm using GlassFish 4.1 and Jersey JAX-RS implementation. 我正在使用GlassFish 4.1和Jersey JAX-RS实现。
You can perform this logic in a ContainerRequestFilter
. 您可以在
ContainerRequestFilter
执行此逻辑。 It pretty common to handle custom security features in here. 在这里处理自定义安全功能非常常见。
Some things to consider 有些事情需要考虑
The class should be annotated with @Priority(Priorities.AUTHENTICATION)
so it is performed before other filters, if any. 该类应使用
@Priority(Priorities.AUTHENTICATION)
进行注释,以便在其他过滤器(如果有)之前执行。
You should make use of the SecurityContext
, inside the filter. 您应该在过滤器内使用
SecurityContext
。 What I do is implement a SecurityContext
. 我所做的是实现一个
SecurityContext
。 You can really implement it anyway you want. 无论如何你都可以真正实现它。
Here's a simple example without any of the security logic 这是一个没有任何安全逻辑的简单示例
@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; }
}
}
A few things to notice 有几点需要注意
SecurityContext
SecurityContext
isUserInRole
method. isUserInRole
方法。 This will be used for authorization. User
class, that implements java.security.Principal
. User
类,它实现了java.security.Principal
。 I returned this custom object SecurityContext
in the ContainerRequestContext
ContainerRequestContext
设置了新的SecurityContext
Now what? 怎么办? Let's look at a simple resource class
我们来看一个简单的资源类
@Path("secure")
public class SecuredResource {
@GET
@RolesAllowed({"ADMIN"})
public String getUsername(@Context SecurityContext securityContext) {
User user = (User)securityContext.getUserPrincipal();
return user.getName();
}
}
A few things to notice: 有几点需要注意:
SecurityContext
is injected into the method. SecurityContext
被注入到方法中。 Principal
and cast it to User
. Principal
并将其投射给User
。 So really you can create any class that implements Principal
, and use this object however you want. Principal
类,并根据需要使用这个对象。 The use of the @RolesAllowed
annotation. 使用
@RolesAllowed
注释。 With Jersey, there is a filter that checks the SecurityContext.isUserInRole
by passing in each value in the @RolesAllowed
annotation to see if the User is allowed to access the resource. 对于Jersey,有一个过滤器通过传入
@RolesAllowed
注释中的每个值来检查SecurityContext.isUserInRole
,以查看是否允许用户访问该资源。
To enable this feature with Jersey, we need to register the RolesAllowedDynamicFeature
要使用Jersey启用此功能,我们需要注册
RolesAllowedDynamicFeature
@ApplicationPath("/api") public class AppConfig extends ResourceConfig { public AppConfig() { packages("packages.to.scan"); register(RolesAllowedDynamicFeature.class); } }
I was searching for an solution which is Jersey independent and works for Wildfly -> found this github example implementation: 我正在寻找一个独立于泽西岛的解决方案,适用于Wildfly - >发现这个github示例实现:
https://github.com/sixturtle/examples/tree/master/jaxrs-jwt-filter https://github.com/sixturtle/examples/tree/master/jaxrs-jwt-filter
It should give you a hint how to solve it clean. 它应该给你一个提示如何解决它干净。
Implement a JWTRequestFilter which implements ContainerRequestFilter https://github.com/sixturtle/examples/blob/master/jaxrs-jwt-filter/src/main/java/com/sixturtle/jwt/JWTRequestFilter.java 实现一个实现ContainerRequestFilter的JWTRequestFilter https://github.com/sixturtle/examples/blob/master/jaxrs-jwt-filter/src/main/java/com/sixturtle/jwt/JWTRequestFilter.java
as stated above and register the filter as resteasy provider in web.xml: 如上所述,并在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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.