【发布时间】:2020-01-21 14:03:44
【问题描述】:
我正在学习使用 JWT 令牌和 Spring Boot 的 Spring Security。我已经正确实施它并且工作正常。但我对 JwtRequestFilter 的工作原理有一个疑问。我已经浏览了几个网站来了解使用 spring boot 的 spring security 并发现了同样的事情。所以让我去主要怀疑。 我在下面添加 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);
}
}
为了验证令牌,我们必须提供 spring UserDetails 对象,并且我们从 jwtUserDetailsService 获取 spring UserDetails 对象。因此,此过滤器将调用的每个请求都会执行令牌验证,我们必须在每个请求上调用 jwtUserDetailsService。 我的疑问在于我的 jwtUserDetailsService 我正在添加几个验证并添加用户权限。因此,在 jwtUserDetailsService 中重复以下步骤。
- 使用数据库中的用户名获取用户。
- 获取用户角色
- 从数据库获取用户权限。
- 为 userDetails 分配权限。
JwtUserDetailsService.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 UserDetails 对象中添加一次角色和权限详细信息,为什么我们需要再次添加它?
【问题讨论】:
-
spring security 5 中已经有了 jwt 过滤器,为什么还要实现自己的过滤器
-
@ThomasAndolf,对不起,我刚刚开始学习这个。所以我不知道 spring security 5 提供了这样的功能。您能否提供任何链接,以便我可以通过它来理解概念。谢谢。
-
太多人用谷歌搜索和阅读旧教程。始终先查看他们自己的文档。其实真的很好docs.spring.io/spring-security/site/docs/current/reference/…
-
@ThomasAndolf,谢谢,我会调查的。
-
@ThomasAndolf 至少他们在谷歌搜索:-)。我正在查看文档,但在列表中没有看到 JWT 过滤器(我见过有人扩展了 UsernamePasswordAuthenticationFilter 或 OncePerFilter)。我在 OAuth 下看到了一个令牌过滤器,但他没有在上面实现 OAuth。 dev.to/d_tomov/…
标签: java spring spring-boot spring-security jwt