jon*_*jon 2 java rest restful-authentication httpresponse jersey-2.0
带有令牌身份验证+基于角色的授权的Jersey 2.22 API(我保护API的方式基于本文的公认答案:使用JAX-RS和Jersey进行基于REST令牌身份验证的最佳实践。最好在阅读之前阅读它试图理解我的问题):
这是我的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>
Run Code Online (Sandbox Code Playgroud)
当我调用任务 Web服务时,流程毫无问题地进入第一个过滤器(AuthenticationFilter)(@Priority(Priorities.AUTHENTICATION)),验证我的令牌,从解码的令牌中获取用户,然后将其注册为委托人然后传入第二个过滤器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());
}
Run Code Online (Sandbox Code Playgroud)
当用户具有正确的角色时,将调用该服务,并且我会收到带有正确信息的正确响应。我的问题是,当我的变量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) {
... }
Run Code Online (Sandbox Code Playgroud)
您应该将此Jersey init-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
注意:如果您不使用web.xml,则ResourceConfig
可以使用property(property, value)
方法。对于Application
子类,您可以覆盖Map<String, Object> getProperties()
public class MyApp extends ResourceConfig {
public MyApp() {
property(ServletProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR, true);
}
}
public class MyApp extends Application {
@Override
public Map<String, Object> getProperties() {
Map<String, Object> props = new HashMap<>();
props.put("jersey.config.server.response.setStatusOverSendError", true);
return props;
}
}
Run Code Online (Sandbox Code Playgroud)