我正在开发基于令牌的REST服务。当用户通过curl使用用户和密码转到../rest/authenticate时,获取有效令牌以使用整个API。
当用户忘记在其他方法中插入用户名,密码或令牌时出现我的问题,因为我没有设法按我的意愿处理身份验证例外。
我可以处理异常但tomcat会获得响应并插入一些我不期望的HTML。
这是tomcat的典型响应。
是否有可能收到200 OK这样没有此HTML代码的响应?
在妈妈那里,这是我的配置:
决定网址是否安全。如果必须保护,请调用身份验证管理器以验证它。如果收到身份验证异常,则调用AuthenticationEntryPoint
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
private final Collection<String> nonTokenAuthUrls = Lists.newArrayList("/rest","/rest/authenticate");
TokenAuthenticationManager tokenAuthenticationManager;
RestAuthenticationEntryPoint restAuthenticationEntryPoint;
public AuthenticationTokenProcessingFilter(TokenAuthenticationManager tokenAuthenticationManager, RestAuthenticationEntryPoint restAuthenticationEntryPoint) {
this.tokenAuthenticationManager = tokenAuthenticationManager;
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
try{
if(!nonTokenAuthUrls.contains(httpRequest.getRequestURI())){ //Auth by token
String hash = httpRequest.getHeader("token");
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(hash, null);
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
SecurityContextHolder.getContext().setAuthentication(tokenAuthenticationManager.authenticate(authentication));
}
response.reset();
chain.doFilter(request, response);
}catch(AuthenticationException authenticationException){
SecurityContextHolder.clearContext();
restAuthenticationEntryPoint.commence(httpRequest, httpResponse, authenticationException);
}
}
public class TokenAuthenticationManager implements AuthenticationManager{
@Autowired
UserService userService;
@Autowired
TokenService tokenService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Object hash = authentication.getPrincipal();
if(hash == null)
throw new BadCredentialsException("Token is required");
User user = tokenService.getUserFromTokenHash((String)hash);
if(user == null)
throw new BadCredentialsException("Non-existent token");
if(!tokenService.validate((String)hash))
throw new BadCredentialsException("Expired Token");
org.springframework.security.core.userdetails.User userDetails = new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getUserGrantedAuthorities(user.getRoles()));
return new UsernamePasswordAuthenticationToken(userDetails, user.getPassword(), getUserGrantedAuthorities(user.getRoles()));
}
此课程正常。收到的代码是未经授权的401,但消息是在tomcat html
中公共类RestAuthenticationEntryPoint实现AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
response.setContentType("application/json");
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage() );
response.getOutputStream().println("{ \"error\": \"" + authenticationException.getMessage() + "\" }");
}
}
也没有调用RestAccessDeniedHanler。这很困难,因为有很多课程需要实施。
我回顾了stackoverflow和其他网站中的一些帖子,我的方法是捕获AuthenticationProcessingFilter中的异常并手动调用AuthenticationEntryPoint。我决定这样做,因为我试图在applicationContext-security.xml中配置它,但没有成功。
<b:bean id="restAuthenticationEntryPoint" class="...web.security.RestAuthenticationEntryPoint" />
<b:bean id="tokenAuthenticationManager" class="...dp.web.security.TokenAuthenticationManager"/>
<b:bean id="AuthenticationTokenProcessingFilter" class="...web.security.AuthenticationTokenProcessingFilter">
<b:constructor-arg type="...dp.web.security.TokenAuthenticationManager" ref="tokenAuthenticationManager"></b:constructor-arg>
<b:constructor-arg type="...dp.web.security.RestAuthenticationEntryPoint" ref="restAuthenticationEntryPoint"></b:constructor-arg>
</b:bean>
<b:bean id="accessDeniedHandler" class="...dp.web.security.RestAccessDeniedHandler">
</b:bean>
<http realm="Protected REST API" pattern="/rest/**" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="restAuthenticationEntryPoint">
<custom-filter ref="AuthenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<access-denied-handler ref="accessDeniedHandler"/>
</http>
如何使用错误代码和消息发送干净的响应?
答案 0 :(得分:2)
您可以在web.xml中使用错误页面拦截Tomcat的错误页面。例如,
<error-page>
<error-code>404</error-code>
<location>/404</location>
</error-page>
现在,您使用RequestMapping将/ 404映射到一个页面,该页面返回您的JSON响应,而不包含任何HTML:
@RequestMapping(value = "/404", method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE})
@ResponseBody
public ResponseEntity<ResponseStatus> handle404() {
HttpStatus status = null;
ResponseStatus responseStatus = new ResponseStatus("404", "Wrong path to resource.");
status = HttpStatus.NOT_FOUND;
ResponseEntity<ResponseStatus> response = new ResponseEntity<ResponseStatus>(responseStatus, status);
return response;
}
这将只返回一个名为Response Status的JSON对象,其中包含错误代码和错误消息作为字段。