Jersey 2.22 API,带有令牌身份验证+基于角色的授权(我保护API的方式基于此帖子中接受的答案:Best practice for REST token-based authentication with JAX-RS and Jersey。在尝试理解我的问题之前阅读它可能更好) :
这是我的 web.xml :
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- LISTENERS -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>JerseySpringServlet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>ca.toto.api.filters</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>ca.toto.api.restapi</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>ca.toto.api.filters.AuthenticationFilter;ca.toto.api.filters.AuthorizationFilter;com.toto.api.restapi.TaskRestService</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JerseySpringServlet</servlet-name>
<url-pattern>/filters/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>JerseySpringServlet</servlet-name>
<url-pattern>/restapi/*</url-pattern>
</servlet-mapping>
当我打电话给我的任务网络服务时,流程会进入第一个过滤器( AuthenticationFilter )而没有任何问题( @Priority(优先级。 AUTHENTICATION)),验证我的令牌,从解码后的令牌中获取用户,然后将其注册为 Principal ,然后传入第二个过滤器 AuthorizationFilter ( @Priority(Priorities.AUTHORIZATION))我从安全上下文中获取用户,获取他的角色,然后检查他是否有权拨打电话。如果是,请在正常情况下退出过滤器,使用 javax.ws.rs.container.ContainerRequestContext 。 abortWith 方法发送状态为403的响应:
@Secured
@Provider
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
...
try {
boolean isAllowed = false;
// Check if the user is allowed to execute the method
// The method annotations override the class annotations
if (methodRoles.isEmpty()) {
logger.info("Checking permissions on CLASS level");
isAllowed = checkPermissions(classRoles);
} else {
logger.info("Checking permissions on METHOD level");
isAllowed = checkPermissions(methodRoles);
}
// Throw an Exception if the user has not permission to execute the method
if(isAllowed == false) {
logger.warn("USER IS NOT ALLOWED TO COMPLETE THE REQUEST. ABORT.");
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
}
} catch (Exception e) {
requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
}
当用户具有正确的角色时,将调用该服务并使用正确的信息获得正确的响应。 我的问题是,当我的变量 isAllowed 等于false时,我得到 404 而不是 403 ,我无法弄清楚原因。 ..
这是我的 TaskRestService 服务定义:
@Path("/tasks")
@Secured({RoleEnum.admin})
public class TaskRestService {
...
@GET
@Produces(MediaType.APPLICATION_JSON)
@Transactional(readOnly = true)
public List<Task> getTasks(@QueryParam("code") String code) {
... }
答案 0 :(得分:4)
您应该将此Jersey-param jersey.config.server.response.setStatusOverSendError
设置为true
。这是它在Javadoc中的陈述
每当响应状态为4xx或5xx时,可以在特定于容器的
sendError
实施中选择setStatus
或Response
。例如。在servlet容器上,Jersey可以调用HttpServletResponse.setStatus(...)
或HttpServletResponse.sendError(...)
。调用
sendError(...)
方法通常会重置实体,响应标头并为指定的状态代码提供错误页面(例如,servlet错误页面配置)。但是,如果要进行后处理响应(例如,通过servlet过滤器),唯一的方法是在容器setStatus(...)
对象上调用Response
。如果属性值为true,则使用方法
Response.setStatus(...)
而不是默认Response.sendError(...)
。属性值的类型为
boolean
。默认值为false
。
所以会发生错误导致容器尝试将您发送到错误页面,当没有配置时,您会得到404.所以当您将属性设置为true
时,会导致使用setStatus
而不是sendError