当前位置: 首页 > 知识库问答 >
问题:

如何访问@RolesAllowed保护的Jersey资源

裴育
2023-03-14
@POST
@Path("/configuration")
@RolesAllowed("admin")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)

我的疑问是如何通过rest客户端以指定的角色访问这个服务。

共有1个答案

商皓
2023-03-14

因此,您似乎设置了RolesAllowedDynamicFeature,但没有身份验证来设置用户和角色。RolesAllowedDynamicFeature所做的是查找SecurityContext并调用SecurityContext.IsUserinRole(<“Admin”>)以查看SecurityContext中的用户是否具有该角色。

我想您不知道securitycontext是如何设置的。有几种方法。第一种是通过servlet身份验证机制。您可以从Java EE教程中了解关于保护Web应用程序的更多信息。

基本上,您需要在服务器上设置一个安全领域或安全域。每台服务器都有自己特定的设置方式。您可以在这里看到一个示例,或者是如何使用Tomcat完成的。

基本上,领域/域包含允许访问web应用程序的用户。这些用户具有关联的角色。当servlet容器进行身份验证时,无论是基本身份验证还是表单身份验证,它都会从凭据中查找用户,如果用户通过了身份验证,则用户及其角色将与请求相关联。Jersey收集这些信息,并将其放入请求securitycontext中。

如果这看起来有点复杂,那么一个更简单的方法就是忘记servlet容器身份验证,只创建一个Jersey过滤器,在这里您自己设置securitycontext。你可以在这里看到一个例子。您可以使用任何您想要的身份验证方案。重要的部分是使用用户信息设置securitycontext,无论您从何处获取这些信息,可能是访问数据存储的服务。

另见:

  • 确保泽西岛的rest服务

下面是使用筛选器的第二个选项的完整示例。测试由Jersey测试框架运行。您可以按原样运行测试

import java.io.IOException;
import java.nio.charset.Charset;
import java.security.Principal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Priority;
import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Priorities;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.DatatypeConverter;

import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.internal.util.Base64;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import org.glassfish.jersey.test.JerseyTest;

import static junit.framework.Assert.*;
import org.junit.Test;

public class BasicAuthenticationTest extends JerseyTest {

    @Provider
    @Priority(Priorities.AUTHENTICATION)
    public static class BasicAuthFilter implements ContainerRequestFilter {
        
        private static final Logger LOGGER = Logger.getLogger(BasicAuthFilter.class.getName());

        @Inject
        private UserStore userStore;

        @Override
        public void filter(ContainerRequestContext requestContext) throws IOException {
            String authentication = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
            if (authentication == null) {
                throw new AuthenticationException("Authentication credentials are required");
            }

            if (!authentication.startsWith("Basic ")) {
                return;
            }
            
            authentication = authentication.substring("Basic ".length());
            String[] values = new String(DatatypeConverter.parseBase64Binary(authentication), 
                                         Charset.forName("ASCII")).split(":");
            if (values.length < 2) {
                throw new WebApplicationException(400);
            }
            
            String username = values[0];
            String password = values[1];
            
            LOGGER.log(Level.INFO, "{0} - {1}", new Object[]{username, password});
            
            User user = userStore.getUser(username);
            if (user == null) {
                throw new AuthenticationException("Authentication credentials are required"); 
            }
            
            if (!user.password.equals(password)) {
                throw new AuthenticationException("Authentication credentials are required");
            }
            
            requestContext.setSecurityContext(new MySecurityContext(user));
        }
    }
    
    static class MySecurityContext implements SecurityContext {
        
        private final User user;
        
        public MySecurityContext(User user) {
            this.user = user;
        }

        @Override
        public Principal getUserPrincipal() {
            return new Principal() {
                @Override
                public String getName() {
                    return user.username;
                }
            };
        }

        @Override
        public boolean isUserInRole(String role) {
            return role.equals(user.role);
        }

        @Override
        public boolean isSecure() { return true; }

        @Override
        public String getAuthenticationScheme() {
            return "Basic";
        }
        
    }

    static class AuthenticationException extends WebApplicationException {

        public AuthenticationException(String message) {
            super(Response
                    .status(Status.UNAUTHORIZED)
                    .header("WWW-Authenticate", "Basic realm=\"" + "Dummy Realm" + "\"")
                    .type("text/plain")
                    .entity(message)
                    .build());
        }
    }

    class User {

        public final String username;
        public final String role;
        public final String password;

        public User(String username, String password, String role) {
            this.username = username;
            this.password = password;
            this.role = role;
        }
    }

    class UserStore {

        public final Map<String, User> users = new ConcurrentHashMap<>();

        public UserStore() {
            users.put("peeskillet", new User("peeskillet", "secret", "USER"));
            users.put("stackoverflow", new User("stackoverflow", "superSecret", "ADMIN"));
        }

        public User getUser(String username) {
            return users.get(username);
        }
    }
    
    private static final String USER_RESPONSE = "Secured User Stuff";
    private static final String ADMIN_RESPONSE = "Secured Admin Stuff";
    private static final String USER_ADMIN_STUFF = "Secured User Admin Stuff";
    
    @Path("secured")
    public static class SecuredResource {
        
        @GET
        @Path("userSecured")
        @RolesAllowed("USER")
        public String getUser() {
            return USER_RESPONSE;
        }
        
        @GET
        @Path("adminSecured")
        @RolesAllowed("ADMIN")
        public String getAdmin() {
            return ADMIN_RESPONSE;
        }
        
        @GET
        @Path("userAdminSecured")
        @RolesAllowed({"USER", "ADMIN"})
        public String getUserAdmin() {
            return USER_ADMIN_STUFF;
        }
    }

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig(SecuredResource.class)
                .register(BasicAuthFilter.class)
                .register(RolesAllowedDynamicFeature.class)
                .register(new AbstractBinder(){
            @Override
            protected void configure() {
                bind(new UserStore()).to(UserStore.class);
            }
        });
    }
    
    static String getBasicAuthHeader(String username, String password) {
        return "Basic " + Base64.encodeAsString(username + ":" + password);
    }
    
    @Test
    public void should_return_403_with_unauthorized_user() {
        Response response = target("secured/userSecured")
                .request()
                .header(HttpHeaders.AUTHORIZATION, 
                        getBasicAuthHeader("stackoverflow", "superSecret"))
                .get();
        assertEquals(403, response.getStatus());
    }
    
    @Test
    public void should_return_200_response_with_authorized_user() {
        Response response = target("secured/userSecured")
                .request()
                .header(HttpHeaders.AUTHORIZATION, 
                        getBasicAuthHeader("peeskillet", "secret"))
                .get();
        assertEquals(200, response.getStatus());
        assertEquals(USER_RESPONSE, response.readEntity(String.class));
    }
    
    @Test
    public void should_return_403_with_unauthorized_admin() {
        Response response = target("secured/adminSecured")
                .request()
                .header(HttpHeaders.AUTHORIZATION, 
                        getBasicAuthHeader("peeskillet", "secret"))
                .get();
        assertEquals(403, response.getStatus());
    }
    
    @Test
    public void should_return_200_response_with_authorized_admin() {
        Response response = target("secured/adminSecured")
                .request()
                .header(HttpHeaders.AUTHORIZATION, 
                        getBasicAuthHeader("stackoverflow", "superSecret"))
                .get();
        assertEquals(200, response.getStatus());
        assertEquals(ADMIN_RESPONSE, response.readEntity(String.class));
    }
}
<dependency>
    <groupId>org.glassfish.jersey.test-framework.providers</groupId>
    <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
    <version>${jersey2.version}</version>
    <scope>test</scope>
</dependency>
 类似资料:
  • 通过向资源服务器出示访问令牌,客户端访问受保护资源。资源服务器必须验证访问令牌,并确保它没有过期且其范围涵盖了请求的资源。资源服务器用于验证访问令牌的方法(以及任何错误响应)超出了本规范的范围,但一般包括资源服务器和授权服务器之间的互动或协调。 客户端使用访问令牌与资源服务器进行证认的方法依赖于授权服务器颁发的访问令牌的类型。通常,它涉及到使用具有所采用的访问令牌类型的规范定义的身份验证方案(如R

  • 从quarkus集装箱码头,我可以使用以下命令访问keycloak服务器 返回200状态;但无法访问受保护的资源。 我在这里做错了什么?

  • 客户端向资源服务器提供访问令牌以访问受保护资源。 资源服务器必须验证并验证访问令牌是否有效且未过期。 发送凭据有两种标准方式 - Bearer Token - 访问令牌只能作为授权HTTP头中的后备选项放在POST请求正文或GET URL参数中。 它们包含在授权标题中,如下所示 - Authorization: Bearer [token-value] 例如 - GET/resource/1 H

  • 问题内容: 我有一个可通过HTTP访问的简单Web API,一些相应的移动应用程序正在读取该数据。现在有人反编译了一个应用程序/嗅探了HTTP流量,将URL转到了我的Web API,并建立了自己的客户端,就像我的客户端一样。 如何确保仅我自己的客户对API的访问权限?即使想到有人在反编译我的应用程序。 服务器和客户端代码更改是一个选择! 问题答案: 服务器和客户端代码更改是一个选择! 首先,您无法

  • 我想做基于令牌的机制,我将有要么温泉或移动应用程序支持多个客户端。 我的web服务引擎和应用程序的用例: 我的web应用程序:客户将注册他们的应用程序,无论是SPA还是移动应用程序。他们将在注册时获得客户id。在SPA或移动应用程序的情况下,只有作为密钥的客户端id会被泄露,因此我只提供客户端id。 Web服务引擎:支持多个客户端,登录客户端各自的应用程序后管理每个用户的会话。 因此,假设有 2

  • 我正在尝试根据通过泽西岛/JAX-RS 公开的资源的角色来设置身份验证。此资源存在于 Glassfish 实例中,在该实例中,基于角色的身份验证(特别是通过@RolesAllowed)当前正在按预期工作。我正在一个 servlet 容器中运行泽西岛: 并且正在对我的资源强制执行基本身份验证;该要求正在按预期强制执行。我还向泽西提供了以下初始化参数: 但是,当我尝试实际添加@Rlet准许注释时,所有