我正在关注一个可以帮助我学习Spring-Boot
的教程。到目前为止一切都很好。但是,在使用JWT
进行保护时,我很挣扎。我很难解释问题的具体出处,因为我还不完全了解Spring-Boot
和JWT
的工作方式。由于某些原因,身份验证无法正常工作:
io.jsonwebtoken.MalformedJwtException:JWT字符串必须恰好包含2个句点字符。找到:0
以下是我认为可能涉及的不同类别:
public class AuthenticationService {
static final long EXPIRATION_TIME = 864_000_00;
static final String SIGNING_KEY = "SecretKey";
static final String PREFIX = "Bearer";
public static void addToken(HttpServletResponse res, String username) {
String JwtToken = Jwts.builder().setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME ))
.signWith(SignatureAlgorithm.HS512, SIGNING_KEY)
.compact();
res.addHeader("Authorization", PREFIX + " " + JwtToken);
res.addHeader("Access-Control-Expose-Headers", "Authorization");
}
public static Authentication getAuthentication(HttpServletRequest request) {
String token = request.getHeader("Authorization");
if(token != null) {
String user = Jwts.parser().setSigningKey(SIGNING_KEY)
.parseClaimsJws(token.replace(PREFIX, "")).getBody().getSubject();
if(user != null) {
return new UsernamePasswordAuthenticationToken(user, null, emptyList());
}
}
return null;
}
}
凭据:
public class AccountCredentials {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
用于登录身份验证的过滤器类:
public class LoginFilter extends AbstractAuthenticationProcessingFilter{
protected LoginFilter(String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException, IOException, ServletException {
AccountCredentials creds = new ObjectMapper().readValue(req.getInputStream(), AccountCredentials.class);
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),
creds.getPassword(), Collections.emptyList()));
}
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException {
// TODO Auto-generated method stub
AuthenticationService.addToken(res, auth.getName());
}
}
处理端点中的认证:
public class AuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
Authentication authentication = AuthenticationService.getAuthentication((HttpServletRequest)request);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
}
}
最后是一个类,它定义对网址的POST
方法请求。
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private UserDetailServiceImpl userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception{
http.cors().and().authorizeRequests().antMatchers(HttpMethod.POST, "/login").permitAll()
.anyRequest().authenticated().and()
.addFilterBefore(new LoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
现在使用Postman
,如果我有一个POST
请求使用正文“ /登录”:
{"username":"someuser", "pastword":"somepassword"}
我应该获得授权。相反,我得到了:
io.jsonwebtoken.MalformedJwtException:JWT字符串必须恰好包含2个句点字符。找到:0
注意:我确保用户名和密码正确。