是否有可能实现简单的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);
}
}
我发现了一种仅使用用户ID ,用户名和<来构建UserPrincipal对象(它实现 UserDetails 接口)的问题的解决方案强大的>授权机构,并且没有例如密码,我无法从JWT令牌本身读取该密码(其余的我可以读取),但是我不确定它是否安全,是否被认为是一种很好的实践解决方案( UserDetails 类需要密码字段,并将其存储为JWT(我认为并不明智)。我需要UserPrincipal实例(实现UserDetails接口)作为 UsernamePasswordAuthenticationToken 的参数来支持,如您在第一段中所见。