java 自定义 JAX-RS 授权 - 在每个请求中使用 JWT
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29766673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Custom JAX-RS authorization - using JWT in each request
提问by D00de
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. Roles based security and existing REALMS and atuhentication methods doesn't fit my requirement.
我有一个 JAX-RS 服务,我希望我的所有用户都可以访问我的服务,但只有那些有权查看结果的用户。基于角色的安全性和现有的 REALMS 和身份验证方法不符合我的要求。
For example:
例如:
- user authenticates against one REST service and I send him JWT token with his ID
- user asks for other resource and sends his JWT with his ID in each request
- I check his user id (from JWT) and if the business logic returns result I send them back, else I send empty result set or specific HTTP status
- 用户针对一项 REST 服务进行身份验证,我向他发送带有他的 ID 的 JWT 令牌
- 用户请求其他资源并在每个请求中发送带有他的 ID 的 JWT
- 我检查他的用户 ID(来自 JWT),如果业务逻辑返回结果,我将它们发回,否则我发送空结果集或特定的 HTTP 状态
Question is: Where should I check for users ID, in some separate filter, security context or in every REST method implementation? How to provide REST methods with this ID, can securityContext be injected in every method after filtering request by ID?
问题是:我应该在哪里检查用户 ID,在某个单独的过滤器、安全上下文中还是在每个 REST 方法实现中?如何提供带有此ID的REST方法,是否可以在通过ID过滤请求后在每个方法中注入securityContext?
I'm using GlassFish 4.1 and Jersey JAX-RS implementation.
我正在使用 GlassFish 4.1 和 Jersey JAX-RS 实现。
回答by Paul Samsotha
You can perform this logic in a ContainerRequestFilter
. It pretty common to handle custom security features in here.
您可以在ContainerRequestFilter
. 在这里处理自定义安全功能很常见。
Some things to consider
需要考虑的一些事项
The class should be annotated with
@Priority(Priorities.AUTHENTICATION)
so it is performed before other filters, if any.You should make use of the
SecurityContext
, inside the filter. What I do is implement aSecurityContext
. You can really implement it anyway you want.
该类应该被注释,
@Priority(Priorities.AUTHENTICATION)
以便它在其他过滤器之前执行,如果有的话。您应该使用
SecurityContext
过滤器内的 , 。我所做的是实现一个SecurityContext
. 你真的可以以任何你想要的方式实现它。
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
需要注意的几件事
- I've created a
SecurityContext
- I've added some roles, and used them for the
isUserInRole
method. This will be used for authorization. - I've created a custom
User
class, that implementsjava.security.Principal
. I returned this custom object - Finally I set the new
SecurityContext
in theContainerRequestContext
- 我创建了一个
SecurityContext
- 我添加了一些角色,并将它们用于
isUserInRole
方法。这将用于授权。 - 我创建了一个自定义
User
类,它实现了java.security.Principal
. 我返回了这个自定义对象 - 最后我
SecurityContext
在ContainerRequestContext
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.- We get the
Principal
and cast it toUser
. So really you can create any class that implementsPrincipal
, and use this object however you want. The use of the
@RolesAllowed
annotation. With Jersey, there is a filter that checks theSecurityContext.isUserInRole
by passing in each value in the@RolesAllowed
annotation to see if the User is allowed to access the resource.To enable this feature with Jersey, we need to register the
RolesAllowedDynamicFeature
@ApplicationPath("/api") public class AppConfig extends ResourceConfig { public AppConfig() { packages("packages.to.scan"); register(RolesAllowedDynamicFeature.class); } }
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); } }
回答by max
I was searching for an solution which is Jersey independent and works for Wildfly -> found this github example implementation:
我正在寻找一个独立于 Jersey 并适用于 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
实现一个 JWTRequestFilter,它实现了 ContainerRequestFilter 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>