Почему нам нужно загружать данные пользователя из БД для каждого запроса при аутентификации JWT с помощью Spring SecuritJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Почему нам нужно загружать данные пользователя из БД для каждого запроса при аутентификации JWT с помощью Spring Securit

Сообщение Anonymous »

В настоящее время я реализую аутентификацию JWT в приложении Spring Boot. В большинстве руководств и примеров я вижу, что метод UserDetailsService.loadUserByUsername вызывается для каждого запроса для проверки токена. Вот фрагмент моего фильтра:

Код: Выделить всё

@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {
private static final String BEARER_PREFIX = "Bearer ";
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final int TOKEN_START_INDEX = 7;

private final JwtService jwtService;
private final UserDetailsService jpaUserDetailsService;

@Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader(AUTHORIZATION_HEADER);
if (hasBearerHeader(authHeader)) {
String token = extractToken(authHeader);
String username = jwtService.extractUsername(token);

if (username != null && !isUserAuthenticated()) {
UserDetails userDetails = jpaUserDetailsService.loadUserByUsername(username);
if (jwtService.isTokenValid(token, userDetails)) {
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
}

filterChain.doFilter(request, response);
}

private boolean hasBearerHeader(final String authHeader) {
return StringUtils.hasText(authHeader) && authHeader.startsWith(BEARER_PREFIX);
}

private String extractToken(String authHeader) {
return Optional.of(authHeader)
.filter(s -> s.length() > TOKEN_START_INDEX)
.map(s -> s.substring(TOKEN_START_INDEX))
.orElseThrow(() -> new BadCredentialsException("Invalid Authorization header: Bearer token is missing or invalid."));
}

private boolean isUserAuthenticated() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null && authentication.isAuthenticated();
}
}
JwtService:

Код: Выделить всё

@Service
public class JwtService {
private static final int TOKEN_VALIDITY_HOURS = 1;
private static final int SECONDS_PER_HOUR = 3600;
private static final int TOKEN_VALIDITY_SECONDS = TOKEN_VALIDITY_HOURS * SECONDS_PER_HOUR;
private static final String ALGORITHM = "HmacSHA256";

@Value("${secret.key}")
private String secretKey;

public String generateToken(final UserDetails userDetails) {
return generateToken(new HashMap(), userDetails);
}

public String generateToken(final Map claims, final UserDetails userDetails) {
Instant currentTime = Instant.now();
Instant expirationTime = currentTime.plusSeconds(TOKEN_VALIDITY_SECONDS);

return Jwts
.builder()
.claims(claims)
.subject(userDetails.getUsername())
.issuedAt(Date.from(currentTime))
.expiration(Date.from(expirationTime))
.signWith(getSecretKey(), Jwts.SIG.HS256)
.compact();
}

public boolean isTokenValid(final String token, final UserDetails userDetails) {
String usernameFromToken = extractUsername(token);
return usernameFromToken.equals(userDetails.getUsername()) && !isTokenExpired(token);
}

private boolean isTokenExpired(final String token) {
return extractExpiration(token).before(new Date());
}

public String extractUsername(final String token) {
return extractClaim(token, Claims::getSubject);
}

public Date extractExpiration(final String token) {
return extractClaim(token, Claims::getExpiration);
}

private  T extractClaim(final String token, final Function  extractor) {
Claims claims = Jwts.parser()
.verifyWith(getSecretKey())
.build()
.parseSignedClaims(token)
.getPayload();

return extractor.apply(claims);

}

private SecretKey getSecretKey() {
byte[] decodedKey = Base64.getDecoder().decode(secretKey);
return new SecretKeySpec(decodedKey, 0, decodedKey.length, ALGORITHM);
}
}
Меня смущает необходимость загрузки данных пользователя из базы данных при каждом запросе. Если токен выдан и проверен, не означает ли это, что пользователь уже аутентифицирован? Разве мы не можем просто проверить подпись и утверждения токена, не обращаясь каждый раз к базе данных?
Я ценю любые подробные объяснения и рекомендации о том, как эффективно обрабатывать аутентификацию JWT в Spring Security.

Подробнее здесь: https://stackoverflow.com/questions/785 ... t-authenti
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»