以下是我到目前为止所做的,但它并没有按照我的意愿行事。我想要的是415,如果内容类型不是json,400杰克逊不能反序列化或验证是错误的。目前当然这都是401s,我在反序列化方面做错了(将错误的类型传递给json)。我想可能有一些方法可以利用Spring MVC在常规控制器下的功能。
@Component
public class JsonAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private final ObjectMapper objectMapper;
private final Validator validator;
protected JsonAuthenticationFilter( final ObjectMapper objectMapper, final Validator validator ) {
super( new AntPathRequestMatcher( "/authentication/password", "POST" ) );
this.objectMapper = objectMapper;
this.validator = validator;
}
@Override
public Authentication attemptAuthentication( final HttpServletRequest request, final HttpServletResponse response )
throws AuthenticationException, IOException, ServletException {
if ( request.getContentType() == null
|| !MediaType.APPLICATION_JSON.isCompatibleWith( MediaType.parseMediaType( request.getContentType() ) ) ) {
response.setStatus( HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE );
throw new AuthenticationServiceException(
"Media Type not supported: " + request.getContentType() );
}
PasswordCredentials credentials = objectMapper.readValue( request.getReader(), PasswordCredentials.class );
DataBinder dataBinder = new DataBinder( credentials );
dataBinder.setValidator( validator );
dataBinder.validate();
AbstractAuthenticationToken authRequest = credentials.toAuthenticationToken();
setDetails( request, authRequest );
return this.getAuthenticationManager().authenticate( authRequest );
}
/**
* Provided so that subclasses may configure what is put into the authentication
* request's details property.
*
* @param request that an authentication request is being created for
* @param authRequest the authentication request object that should have its details
* set
*/
protected void setDetails( HttpServletRequest request, AbstractAuthenticationToken authRequest ) {
authRequest.setDetails( authenticationDetailsSource.buildDetails( request ) );
}
@Override
@Autowired
public void setAuthenticationManager( final AuthenticationManager authenticationManager ) {
super.setAuthenticationManager( authenticationManager );
}
}
答案 0 :(得分:0)
我猜您正在使用JWT身份验证,或者至少使用某种基于令牌的身份验证,对吗?您最好使用@RestController
将身份验证委派给authenticationManager
,而不是使用较低级别的过滤器语义。
这是我之前使用的控制器,经过一些修改后符合您的DTO。你会发现它看起来很像the suggested JHipster example:
@RestController
@RequestMapping(value = "/api")
public class LoginController {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final AuthenticationManager authenticationManager;
private final TokenAuthenticationService tokenAuthenticationService;
public LoginController(
final AuthenticationManager authenticationManager,
final TokenAuthenticationService tokenAuthenticationService) {
this.authenticationManager = authenticationManager;
this.tokenAuthenticationService = tokenAuthenticationService;
}
@RequestMapping(
value = "/login",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE) // will cause 415 errors
public ResponseEntity<String> authenticate(
@Valid @RequestBody PasswordCredentials request) { // validated implicitly
try {
final User principal = doAuthenticate(request);
return ResponseEntity.ok(tokenFor(principal));
} catch (Exception e) {
logger.error("Error authenticating user", e);
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
private String tokenFor(final User principal) {
return tokenAuthenticationService.createTokenForUser(principal);
}
private User doAuthenticate(PasswordCredentials request) {
final Authentication authentication = request.toAuthenticationToken();
final Authentication authenticated = authenticationManager.authenticate(authentication);
return (User) authenticated.getPrincipal();
}
}
要了解Spring控制器如何解析,解析和验证JSON请求体参数,您应该查看RequestResponseBodyMethodProcessor,特别是其resolveArgument
方法,并在过滤器中实现类似的功能。但是,由于您的过滤器不是控制器,因此您应该通过删除对MethodParameter
参数的所有引用来调整代码以满足您的需求。