是否可以实现简单的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接口),仅具有用户ID、用户名和授予的权限,而没有例如密码,我无法从JWT标记本身读取这些密码(剩下的我可以),但我不确定它是否安全,是否被认为是一个良好的实践解决方案,(UserDetails类需要密码字段,我认为存储它是不明智的)。我需要UserPrincipal示例(实作UserDetails界面)以支援作为UsernamePasswordAuthenticationToken的参数,如您在第一段中所见。
1条答案
按热度按时间cgfeq70w1#
一种方法可以如下具有两个滤波器。
这样,您将只在登录请求期间调用db,而不是为所有其他api端点调用。