自定义 JAX-RS 授权 - 在每个请求中使用 JWT [英] Custom JAX-RS authorization - using JWT in each request

查看:21
本文介绍了自定义 JAX-RS 授权 - 在每个请求中使用 JWT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 JAX-RS 服务,我希望我的所有用户都可以访问我的服务,但只有有权查看结果的用户才能访问我的服务.基于角色的安全性和现有的 REALMS 和身份验证方法不符合我的要求.

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.

例如:

  1. 用户针对一项 REST 服务进行身份验证,然后我向他发送带有他的 ID 的 JWT 令牌
  2. 用户请求其他资源并在每个请求中发送带有他的 ID 的 JWT
  3. 我检查了他的用户 ID(来自 JWT),如果业务逻辑返回结果,我将它们发回,否则我发送空结果集或特定的 HTTP 状态

问题是:我应该在哪里检查用户 ID,在某个单独的过滤器、安全上下文中还是在每个 REST 方法实现中?如何给REST方法提供这个ID,是否可以通过ID过滤请求后在每个方法中注入securityContext?

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?

我正在使用 GlassFish 4.1 和 Jersey JAX-RS 实现.

I'm using GlassFish 4.1 and Jersey JAX-RS implementation.

推荐答案

您可以在 ContainerRequestFilter.在这里处理自定义安全功能很常见.

You can perform this logic in a ContainerRequestFilter. It pretty common to handle custom security features in here.

需要考虑的一些事项

  1. 该类应使用 进行注释@Priority(Priorities.AUTHENTICATION) 所以它在其他过滤器之前执行,如果有的话.

  1. The class should be annotated with @Priority(Priorities.AUTHENTICATION) so it is performed before other filters, if any.

您应该使用 SecurityContext,在过滤器内.我所做的是实现一个 SecurityContext.你真的可以以任何你想要的方式实现它.

You should make use of the SecurityContext, inside the filter. What I do is implement a 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; }   
    }
}

注意事项

  • 我创建了一个 SecurityContext
  • 我添加了一些角色,并将它们用于 isUserInRole 方法.这将用于授权.
  • 我创建了一个自定义 User 类,它实现了 java.security.Principal.我返回了这个自定义对象
  • 最后我在 ContainerRequestContext
  • 中设置了新的 SecurityContext
  • 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 implements java.security.Principal. I returned this custom object
  • Finally I set the new SecurityContext in the 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();
    }
}

需要注意的几点:

  • SecurityContext 被注入到方法中.
  • 我们获取Principal 并将其转换为User.因此,您实际上可以创建任何实现 Principal 的类,并根据需要使用该对象.
  • @RolesAllowed 注释的使用.在 Jersey 中,有一个过滤器通过传入 @RolesAllowed 注释中的每个值来检查 SecurityContext.isUserInRole,以查看是否允许用户访问资源.

  • SecurityContext is injected into the method.
  • We get the Principal and cast it to User. So really you can create any class that implements Principal, and use this object however you want.
  • The use of the @RolesAllowed annotation. 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 中启用此功能,我们需要注册 RolesAllowedDynamicFeature

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);
    }
}

这篇关于自定义 JAX-RS 授权 - 在每个请求中使用 JWT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆