Java 如何访问@RolesAllowed保护的Jersey资源
我们正在测试通过postman REST客户端在jersey开发的REST Web服务。它是一种POST方法,并用Java 如何访问@RolesAllowed保护的Jersey资源,java,jersey,jersey-2.0,postman,Java,Jersey,Jersey 2.0,Postman,我们正在测试通过postman REST客户端在jersey开发的REST Web服务。它是一种POST方法,并用@RolesAllowed注释。该方法的完整注释如下所示: @POST @Path("/configuration") @RolesAllowed("admin") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) 当我请求这个http://baseurl/configuratio
@RolesAllowed
注释。该方法的完整注释如下所示:
@POST
@Path("/configuration")
@RolesAllowed("admin")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
当我请求这个http://baseurl/configuration
对于预期的HTTP正文内容,我得到了403
响应(这是预期的,因为它似乎只允许管理员使用)
我的疑问是如何通过rest客户端使用指定的角色访问此服务。因此,您似乎设置了
角色AllowedDynamicFeature
,但在设置用户和角色时没有进行身份验证。RolesAllowedDynamicFeature
所做的是查找SecurityContext
,并调用SecurityContext.isUserInRole()
以查看SecurityContext
中的用户是否具有该角色
我想您不知道如何设置SecurityContext
。有两种方法。第一种是通过servlet身份验证机制。您可以在JavaEE教程中看到更多
基本上,您需要在服务器上设置安全域或安全域。每台服务器都有自己特定的设置方式。您可以看到一个或如何使用Tomcat来完成
基本上,领域/域包含允许访问web应用的用户。这些用户具有关联的角色。当servlet容器进行身份验证时,无论是基本身份验证还是表单身份验证,它都会从凭据中查找用户,如果用户经过身份验证,则用户及其角色与请求关联。Jersey收集此信息并将其放入请求的SecurityContext
如果这看起来有点复杂,那么更简单的方法就是忘记servlet容器身份验证,创建一个Jersey过滤器,您可以自己设置SecurityContext
。你可以看到一个例子。您可以使用您想要的任何身份验证方案。重要的部分是使用用户信息设置SecurityContext
,无论从何处获取,可能是访问数据存储的服务
另请参见:
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));
}
}
import java.io.IOException;
导入java.nio.charset.charset;
导入java.security.Principal;
导入java.util.Map;
导入java.util.concurrent.ConcurrentHashMap;
导入java.util.logging.Level;
导入java.util.logging.Logger;
导入javax.annotation.Priority;
允许导入javax.annotation.security.roles;
导入javax.inject.inject;
导入javax.ws.rs.GET;
导入javax.ws.rs.Path;
导入javax.ws.rs.Priorities;
导入javax.ws.rs.WebApplicationException;
导入javax.ws.rs.container.ContainerRequestContext;
导入javax.ws.rs.container.ContainerRequestFilter;
导入javax.ws.rs.core.HttpHeaders;
导入javax.ws.rs.core.Response;
导入javax.ws.rs.core.Response.Status;
导入javax.ws.rs.core.SecurityContext;
导入javax.ws.rs.ext.Provider;
导入javax.xml.bind.DatatypeConverter;
导入org.glassfish.hk2.utilities.binding.AbstractBinder;
导入org.glassfish.jersey.internal.util.Base64;
导入org.glassfish.jersey.server.ResourceConfig;
导入org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
导入org.glassfish.jersey.test.JerseyTest;
导入静态junit.framework.Assert.*;
导入org.junit.Test;
公共类基本身份验证测试扩展了Jersey测试{
@提供者
@优先级(Priorities.AUTHENTICATION)
公共静态类BasicAuthFilter实现ContainerRequestFilter{
私有静态最终记录器Logger=Logger.getLogger(BasicAuthFilter.class.getName());
@注入
私有用户存储用户存储;
@凌驾
公共无效筛选器(ContainerRequestContext requestContext)引发IOException{
字符串身份验证=requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
if(身份验证==null){
抛出新的AuthenticationException(“需要身份验证凭据”);
}
if(!authentication.startsWith(“Basic”)){
返回;
}
authentication=authentication.substring(“Basic”.length());
字符串[]值=新字符串(DatatypeConverter.parseBase64Binary(身份验证),
字符集.forName(“ASCII”).split(“:”);
如果(值。长度<2){
抛出新的WebApplicationException(400);
}
字符串用户名=值[0];
字符串密码=值[1];
log(Level.INFO,“{0}-{1}”,新对象[]{username,password});
User=userStore.getUser(用户名);
if(user==null){
抛出新的AuthenticationException(“需要身份验证凭据”);
}
如果(!user.password.equals(password)){
抛出新的AuthenticationException(“需要身份验证凭据”);
}
setSecurityContext(新的MySecurityContext(用户));
}
}
静态类MySecurityContext实现SecurityContext{
私有最终用户;
公共MySecurityContext(用户){
this.user=用户;
}
@凌驾
公共主体getUserPrincipal(){
返回新主体(){
@凌驾
公共字符串getName(){
返回user.username;
}
};
}
@凌驾
公共布尔值isUserInRole(字符串角色){
返回role.equals(user.role);
}
@凌驾
酒吧
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>