Можно ли реализовать простую аутентификацию JWT (не заботясь о аннулировании токенов - я сделаю это в кеше) без вызовов базы данных для загрузки пользователя в контекст безопасности? Я вижу, что моя текущая реализация попадает в базу данных при каждом вызове API (чтобы загрузить пользователя в контекст безопасности). Ниже вы можете увидеть часть реализации JwtAuthenticationFilter расширение OncePerRequestFilter :
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
А вот вызов базы данных, которого я хотел бы избежать (при каждом аутентифицированном вызове api):
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
UserRepository userRepository;
// This method is used by JWTAuthenticationFilter
@Transactional
public UserDetails loadUserById(Long id) {
User user = userRepository.findById(id).orElseThrow(
() -> new UsernameNotFoundException("User not found with id : " + id)
);
return UserPrincipal.create(user);
}
}
Я нашел какое-то решение проблемы для создания объекта UserPrincipal (он реализует UserDetails интерфейс) только с идентификатором пользователя , username и предоставлено власти и без пароль , который я не могу прочитать из самого токена JWT (остальное могу), но я не уверен, является ли он безопасным и считается ли это хорошим решением ( UserDetails класс требует поле пароля и его хранение JWT не было бы разумно, я думаю). Мне нужен экземпляр UserPrincipal (реализующий интерфейс UserDetails) для поддержки в качестве аргумента UsernamePasswordAuthenticationToken , как вы можете видеть в первом абзаце.