我正在尝试为在移动应用程序上用Facebook登录的用户生成JWT令牌。我将facebook数据发送到此功能:
@PostMapping("/facebook")
public void registerWithFacebook(@RequestBody User user, HttpServletRequest request, HttpServletResponse response){
User loggingInUser = this.userRepository.findByUsername(user.getUsername());
if( loggingInUser == null){
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
user.setBlocked(false);
this.userRepository.save(user);
}
//Generate JWT token for user
JWTAuthenticationFilter jwtAuthenticationFilter = new JWTAuthenticationFilter(this.authenticationManager, this.userRepository);
jwtAuthenticationFilter.attemptAuthentication(request, response);
}
然后从我的
attemptAuthentication
类中调用JWTAuthenticationFilter
:public class JWTAuthenticationFilter extends
UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private UserRepository userRepository;
public JWTAuthenticationFilter() {
}
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/login", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
try {
User creds = new ObjectMapper()
.readValue(request.getInputStream(), User.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
new ArrayList<>())
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
String token = Jwts.builder()
.setSubject(((org.springframework.security.core.userdetails.User) authResult.getPrincipal()).getUsername())
.setExpiration(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SecurityConstants.JWT_SECRET.getBytes())
.compact();
response.addHeader(SecurityConstants.HEADER_STRING, token);
String username = JWTAuthorizationFilter.getUsernameFromToken(token);
User user = this.userRepository.findByUsername(username);
Map<String, String> responseBody = new HashMap<>();
responseBody.put("token", token);
responseBody.put("blocked", Boolean.toString(user.isBlocked()));
responseBody.put("paid", Boolean.toString(user.isPaid()));
responseBody.put("endSubscription", user.getEndSubscribtionDate() + "");
String jsonResponse = new ObjectMapper().writeValueAsString(responseBody);
response.getWriter().write(jsonResponse);
}
}
但是
attemptAuthentication
类中的JWTAuthenticationFilter
方法会引发以下错误:在以下代码行中的java.io.IOException: Stream closed
: User creds = new ObjectMapper()
.readValue(request.getInputStream(), User.class);
如果我通过HTTP请求调用
attemptAuthentication
方法,它可以正常工作。什么是或可能是仅当从另一个类调用流关闭异常时才得到它的问题?谢谢!
最佳答案
你用
@RequestBody User user
对于第一种情况,Spring框架已经处理了
HttpServletRequest
实例的输入流(默认情况下只能发生一次),解析数据并将user
实例注入到处理程序中。因此,在调用处理程序时将关闭输入流。您可以重载
attemptAuthentication
方法,并将用户实例作为参数传递。我想您在第二种情况下没有任何Spring映射,因此输入流保持“不变”,并且您可以在身份验证方法中对其进行处理。