Я нашел этот учебник на github для реализации JWT с Angular 8 и springboot2. но, выполняя то же самое, я сталкиваюсь с исключением, приведенным ниже.
io.jsonwebtoken.MalformedJwtException: JWT strings must contain exactly 2 period characters. Found: 0
при дальнейшей отладке, это исключение исходит от DefaultJwtParser. java, который является одним из классов в библиотеке JWT
@Override
public Jwt parse(String jwt) throws ExpiredJwtException, MalformedJwtException, SignatureException {
Assert.hasText(jwt, "JWT String argument cannot be null or empty.");
String base64UrlEncodedHeader = null;
String base64UrlEncodedPayload = null;
String base64UrlEncodedDigest = null;
int delimiterCount = 0;
StringBuilder sb = new StringBuilder(128);
for (char c : jwt.toCharArray()) {
if (c == SEPARATOR_CHAR) {
CharSequence tokenSeq = Strings.clean(sb);
String token = tokenSeq!=null?tokenSeq.toString():null;
if (delimiterCount == 0) {
base64UrlEncodedHeader = token;
} else if (delimiterCount == 1) {
base64UrlEncodedPayload = token;
}
delimiterCount++;
sb.setLength(0);
} else {
sb.append(c);
}
}
if (delimiterCount != 2) {
String msg = "JWT strings must contain exactly 2 period characters. Found: " + delimiterCount;
throw new MalformedJwtException(msg);
}
это означает, что токен должен быть в формате 'Bearer ab c .def.ghi', но в соответствии с руководством он будет похож на 'Bearer Y2xpZW50OmNsaWVudA ==', пока я выполняю вход в систему.
Angular код
login(user: User): Observable<any> {
const headers = new HttpHeaders(user ? {
authorization:'Bearer '+ btoa(user.username + ':' + user.password)
}:{});
return this.http.get<any> (API_URL + "login", {headers:headers}).pipe(
map(response => {
console.log("map"+response);
if(response) {
localStorage.setItem('currentUser', JSON.stringify(response));
this.currentUserSubject.next(response);
}
return response;
})
);
}
Java код
@Component
public class JwtTokenProvider
{
@Value("${app.jwt.secret}")
private String jwtSecret;
@Value("${app.jwt.token.prefix}")
private String jwtTokenPrefix;
@Value("${app.jwt.header.string}")
private String jwtHeaderString;
@Value("${app.jwt.expiration-in-ms}")
private String jwtExpirationInMs;
public String generateToken(Authentication authentication)
{
String authororities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.joining());
return Jwts.builder().setSubject(authentication.getName()).claim("roles", authororities)
.setExpiration(new Date(System.currentTimeMillis() + jwtExpirationInMs))
.signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
}
public Authentication getAuthentication(HttpServletRequest request)
{
String token = resolveToken(request);
if (token == null)
{
return null;
}
Claims claim = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
String username = claim.getSubject();
List<GrantedAuthority> authorities = Arrays.stream(claim.get("roles").toString().split(","))
.map(role -> role.startsWith("ROLE_") ? role : "ROLE_" + role)
.map(SimpleGrantedAuthority::new).collect(Collectors.toList());
return username != null
? new UsernamePasswordAuthenticationToken(username, null, authorities)
: null;
}
public boolean validateToken(HttpServletRequest request)
{
String token = resolveToken(request);
if (token == null)
{
return false;
}
Claims claim = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
if (claim.getExpiration().before(new Date()))
{
return false;
}
return true;
}
private String resolveToken(HttpServletRequest request)
{
String bearerToken = request.getHeader(jwtHeaderString);
if (bearerToken != null && bearerToken.startsWith(jwtTokenPrefix))
{
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
Я уже пытался удалить «Носитель» из заголовка авторизации, но все не работает.
Пожалуйста, дайте мне знать, если нужны какие-либо другие детали