Nel*_*ves 6 spring spring-security spring-boot
我正在尝试使我的 Spring Boot 1.5.x REST API 项目与 2.xx 兼容,而不会破坏大量代码。我被困在我曾经使用的基于过滤器的 JWT Spring Security 实现中:
为了通过“/login”端点对凭据进行身份验证,我曾经扩展UsernamePasswordAuthenticationFilter如下:
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private JWTUtil jwtUtil;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil) {
this.authenticationManager = authenticationManager;
this.jwtUtil = jwtUtil;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req,
HttpServletResponse res) throws AuthenticationException {
try {
CredenciaisDTO creds = new ObjectMapper().readValue(req.getInputStream(), CredenciaisDTO.class);
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(creds.getEmail(), creds.getSenha(), new ArrayList<>());
Authentication auth = authenticationManager.authenticate(authToken);
return auth;
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth) throws IOException, ServletException {
String username = ((UserSS) auth.getPrincipal()).getUsername();
String token = jwtUtil.generateToken(username);
res.addHeader("Authorization", "Bearer " + token);
res.addHeader("access-control-expose-headers", "Authorization");
}
}
Run Code Online (Sandbox Code Playgroud)
另外,为了授权beared-token请求,我曾经扩展BasicAuthenticationFilter如下:
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
private JWTUtil jwtUtil;
private UserDetailsService userDetailsService;
public JWTAuthorizationFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil, UserDetailsService userDetailsService) {
super(authenticationManager);
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws IOException, ServletException {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
UsernamePasswordAuthenticationToken auth = getAuthentication(header.substring(7));
if (auth != null) {
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthentication(String token) {
if (jwtUtil.isValid(token)) {
String username = jwtUtil.getUsername(token);
UserDetails user = userDetailsService.loadUserByUsername(username);
return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
一切都按预期工作:
使用错误凭据请求 /login 会返回 401 并带有标准“未经授权/身份验证失败:错误凭据”对象。
未经授权的承载令牌请求BasicAuthenticationFilter
使用标准的“禁止/访问被拒绝”对象返回 403。
但是,如果我在 Spring Boot 2.0.0 项目中使用该代码,请求 do /login 将返回 403 并带有空体响应。
这篇文章建议包含http.exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));在configure安全配置类的方法中。这样我可以为 /login 请求获得 401,但它仍然返回空体响应(而不是标准的“未授权”错误对象)。此外,现在所有未经授权的请求BasicAuthenticationFilter也返回带有空体响应的 401(而正确的应该返回带有标准“禁止”错误对象内部的 403)。
我怎样才能恢复我以前的理想行为?
知道了。这里的答案是不必要的。为了解决我的问题,我实施了一个AuthenticationFailureHandler:
public class JWTAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
response.setStatus(401);
response.setContentType("application/json");
response.getWriter().append(json());
}
private String json() {
long date = new Date().getTime();
return "{\"timestamp\": " + date + ", "
+ "\"status\": 401, "
+ "\"error\": \"Unauthorized\", "
+ "\"message\": \"Authentication failed: bad credentials\", "
+ "\"path\": \"/login\"}";
}
}
Run Code Online (Sandbox Code Playgroud)
然后将其注入UsernamePasswordAuthenticationFilter:
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
(...)
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, JWTUtil jwtUtil) {
super.setAuthenticationFailureHandler(new JWTAuthenticationFailureHandler());
(...)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5131 次 |
| 最近记录: |