Custom JAX-RS authorization - using JWT in each request

后端 未结 2 1629
天命终不由人
天命终不由人 2020-12-02 12:31

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 atuhe

相关标签:
2条回答
  • 2020-12-02 13:28

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

    Some things to consider

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

    2. 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; }   
        }
    }
    

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

    A few things to notice:

    • 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.

      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);
          }
      }
      
    0 讨论(0)
  • 2020-12-02 13:29

    I was searching for an solution which is Jersey independent and works for Wildfly -> found this github example implementation:

    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

    as stated above and register the filter as resteasy provider in web.xml:

    <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>
    
    0 讨论(0)
提交回复
热议问题