gpt4 book ai didi

java - 带有 JWT token 的 Spring Security 在每个请求上加载 spring UserDetails 对象

转载 作者:太空宇宙 更新时间:2023-11-04 09:23:31 25 4
gpt4 key购买 nike

我正在使用 JWT token 和 Spring Boot 学习 Spring Security。我已经正确实现并且运行良好。但我对 JwtRequestFilter 的工作原理有一个疑问。我浏览了几个网站来了解 Spring Security 和 Spring Boot 并发现了同样的事情。那么让我来谈谈主要疑问。我在下面添加 JwtRequestFilter 文件。

JwtRequestFilter.java

@Component
public class JwtRequestFilter extends OncePerRequestFilter {

@Autowired
private JwtUserDetailsService jwtUserDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

final String requestTokenHeader = request.getHeader("Authorization");

String username = null;
String jwtToken = null;

// JWT Token is in the form "Bearer token". Remove Bearer word and get
// only the Token
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
System.out.println("JWT Token has expired");
}
} else {
logger.warn("JWT Token does not begin with Bearer String");
}
// Once we get the token validate it.
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// This below line is calling on every request
UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
// if token is valid configure Spring Security to manually set
// authentication
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// After setting the Authentication in the context, we specify
// that the current user is authenticated. So it passes the
// Spring Security Configurations successfully.
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
filterChain.doFilter(request, response);
}

}

正如突出显示的那样,为了验证 token ,我们必须提供 spring UserDetails 对象,并且我们正在从 jwtUserDetailsS​​ervice 获取 spring UserDetails 对象。因此,此过滤器将调用每个请求,然后将执行 token 验证,并且我们必须对每个请求调用 jwtUserDetailsS​​ervice。我的疑问是在我的 jwtUserDetailsS​​ervice 中,我添加了一些验证并添加了用户权限。因此,对于每个请求,都会在 jwtUserDetailsS​​ervice 中重复以下步骤。

  1. 使用数据库中的用户名获取用户。
  2. 获取用户角色
  3. 从数据库获取用户权限。
  4. 为 userDetails 分配权限。

JwtUserDetailsS​​ervice.java

@Service("jwtUserDetailsService")
@Transactional
public class JwtUserDetailsService implements UserDetailsService {

@Autowired
private UserRepository userRepository;

@Autowired
private IUserService service;

@Autowired
private MessageSource messages;

@Autowired
private RoleRepository roleRepository;

@Override
public UserDetails loadUserByUsername(String email)
throws UsernameNotFoundException {

User user = userRepository.findByEmail(email);
if (user == null) {
return new org.springframework.security.core.userdetails.User(
" ", " ", true, true, true, true,
getAuthorities(Arrays.asList(
roleRepository.findByName("ROLE_USER"))));
}

return new org.springframework.security.core.userdetails.User(
user.getEmail(), user.getPassword(), user.isEnabled(), true, true,
true, getAuthorities(user.getRoles()));
}

private Collection<? extends GrantedAuthority> getAuthorities(
Collection<Role> roles) {

return getGrantedAuthorities(getPrivileges(roles));
}

private List<String> getPrivileges(Collection<Role> roles) {

List<String> privileges = new ArrayList<>();
List<Privilege> collection = new ArrayList<>();
for (Role role : roles) {
collection.addAll(role.getPrivileges());
}
for (Privilege item : collection) {
privileges.add(item.getName());
}
return privileges;
}

private List<GrantedAuthority> getGrantedAuthorities(List<String> privileges) {
List<GrantedAuthority> authorities = new ArrayList<>();
for (String privilege : privileges) {
authorities.add(new SimpleGrantedAuthority(privilege));
}
return authorities;
}
}

因此,对于每个请求,这些查询都会执行。有更好的方法吗?因为一旦我在 Spring UserDetails 对象中添加用户权限,为什么我们需要对每个请求再次执行此操作。或者那些仅具有请求范围。我曾在 spring mvc 上工作过,一旦我们在 spring UserDetails 对象中添加权限,它就会一直存在,直到我点击注销,这意味着它将存在于 spring 安全上下文中,直到我们将其删除。 Spring Boot 中也会一样吗?如果我在 Spring UserDetails 对象中添加一次角色和权限详细信息,为什么我们需要再次添加它?

最佳答案

So every request this filter will call then token verification will perform and we have to call jwtUserDetailsService on every request.

这不可能是正确的,因为您有一个条件 if (SecurityContextHolder.getContext().getAuthentication() == null)

因此,第一次验证 token 时,您会查询用户详细信息服务,获取所有授权并将它们设置到安全上下文(您已经在执行此操作:SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);)。

此外,使用 JWT 身份验证,您通常甚至不需要访问任何用户详细信息服务,因为理想情况下所有授权都应包含在 token 本身中。因此,您唯一需要做的就是验证 token 的签名。

关于java - 带有 JWT token 的 Spring Security 在每个请求上加载 spring UserDetails 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58029611/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com