gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-31 08:11:50 27 4
gpt4 key购买 nike

我们正在通过 postman 休息客户端测试在 Jersey 开发的 REST 网络服务。它是一个 POST 方法,用 @RolesAllowed 注释。该方法完整注解如下:

@POST
@Path("/configuration")
@RolesAllowed("admin")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)

当我用预期的 HTTP 正文内容请求此 http://baseurl/configuration 时,我得到了 403 响应(这是预期的,因为它只允许管理员使用看起来)。

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

最佳答案

看来您设置了 RolesAllowedDynamicFeature ,但您没有进行身份验证来设置用户和角色。什么RolesAllowedDynamicFeature确实是查找 SecurityContext , 并调用 SecurityContext.isUserInRole(<"admin">)查看用户是否在 SecurityContext有作用。

我想你不知道 SecurityContext已设置。有几种方法。第一种是通过 servlet 认证机制。您可以在 Securing Web Applications 查看更多信息来自 Java EE 教程。

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

基本上,领域/域包含允许访问网络应用程序的用户。这些用户具有关联的角色。 servlet容器在做认证的时候,不管是Basic认证还是Form认证,都会从credentials中查找用户,如果用户通过了认证,那么这个用户和它的角色就会和请求相关联。 Jersey 收集这些信息并将其放入 SecurityContext对于请求。

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

另请参阅:

更新

这是使用过滤器的第二个选项的完整示例。测试由 Jersey Test Framework 运行.您可以按原样运行测试

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>

关于java - 如何访问受@RolesAllowed 保护的 Jersey 资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32817210/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com