[[已编辑]] JWT spring 安全性:如何让 .hasRole() 或 .hasAuthority() 读取角色,它们查看用户角色
[[Edited]] JWT spring security: How to have roles be read by .hasRole() or .hasAuthority(), where they look at the user roles
我正在尝试使用 HTTP 配置中的角色向 spring 执行器服务添加授权,但它不起作用,响应是“禁止的 403”,这意味着用户未经授权。
所以我的问题是 .hasRole() 在使用 JWT 令牌
时究竟在哪里找到登录的用户角色
这是 class 中的 config 方法,它扩展了 WebSecurityConfigurerAdapter class
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new JwtTokenVerifier(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/**").hasRole("ACTUATOR")
.anyRequest()
.authenticated()
.and()
.formLogin().disable();
}
这里我把角色放在了JWT Token中
public String generateJwtToken(UserDetailsImpl userDetails) {
Map<String, Object> claims = new HashMap<>();
Set<String> Userroles = new HashSet<>();
Role r1 = new Role();
r1.setDescription("ROLE_ACTUATOR");
r1.setId(1L);
Set<Role> roles = new HashSet<>();
roles.add(r1);
for(Role role:roles){
Userroles.add(role.getDescription());
}
claims.put("Roles",Userroles.toArray());
claims.put("userId", userDetails.getId());
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(java.sql.Date.valueOf(LocalDate.now().plusDays(getTokenExpirationAfterDays())))
.signWith(Keys.hmacShaKeyFor(getSecretKey().getBytes())).compact();
}
所以有什么问题或缺失?提前致谢
这是 JWT 自定义过滤器的更新:
public class JwtTokenVerifier extends OncePerRequestFilter {
private JwtConfig jwtConfig;
public JwtTokenVerifier(JwtConfig jwtConfig) {
super();
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authorizationHeader == null || authorizationHeader.isEmpty() || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
String requestParam = request.getParameter("token");
if (requestParam != null && !requestParam.isEmpty() && requestParam.startsWith(jwtConfig.getTokenPrefix())) {
authorizationHeader = requestParam;
} else {
filterChain.doFilter(request, response);
return;
}
}
try {
if (jwtConfig.validateJwtToken(authorizationHeader)) {
String username = jwtConfig.getUserNameFromJwtToken(authorizationHeader);
Authentication auth = new UsernamePasswordAuthenticationToken(username, new WebAuthenticationDetailsSource().buildDetails(request), null);
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
}
filterChain.doFilter(request, response);
}
}
在 WebSecurityConfigurerAdapter
扩展中,我看到 ACTUATOR
,但在用户详细信息定义中我看到 ROLE_ACTUATOR
。这是不匹配吗?
感谢@SteveRiesenberg,正如在聊天中所说 “如果您的自定义 JWT 过滤器不处理角色,那就是问题所在。执行身份验证时必须填充角色(权限) ."
因此,由于角色未在过滤器中处理,因此它们未通过安全链。
过滤器的代码编辑如下:
UserDetailsImpl userDetails = (UserDetailsImpl) userDetailsService.loadUserByUsername(username);
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
Authentication auth = new UsernamePasswordAuthenticationToken(username, new WebAuthenticationDetailsSource().buildDetails(request), authorities);
其中权限传递给UsernamePasswordAuthenticationToken
,UserDetailsImpl
是由spring
提供的UserDetails
class的实现
我正在尝试使用 HTTP 配置中的角色向 spring 执行器服务添加授权,但它不起作用,响应是“禁止的 403”,这意味着用户未经授权。
所以我的问题是 .hasRole() 在使用 JWT 令牌
这是 class 中的 config 方法,它扩展了 WebSecurityConfigurerAdapter class
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(new JwtTokenVerifier(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/auth/**").permitAll()
.antMatchers("/actuator/**").hasRole("ACTUATOR")
.anyRequest()
.authenticated()
.and()
.formLogin().disable();
}
这里我把角色放在了JWT Token中
public String generateJwtToken(UserDetailsImpl userDetails) {
Map<String, Object> claims = new HashMap<>();
Set<String> Userroles = new HashSet<>();
Role r1 = new Role();
r1.setDescription("ROLE_ACTUATOR");
r1.setId(1L);
Set<Role> roles = new HashSet<>();
roles.add(r1);
for(Role role:roles){
Userroles.add(role.getDescription());
}
claims.put("Roles",Userroles.toArray());
claims.put("userId", userDetails.getId());
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(java.sql.Date.valueOf(LocalDate.now().plusDays(getTokenExpirationAfterDays())))
.signWith(Keys.hmacShaKeyFor(getSecretKey().getBytes())).compact();
}
所以有什么问题或缺失?提前致谢
这是 JWT 自定义过滤器的更新:
public class JwtTokenVerifier extends OncePerRequestFilter {
private JwtConfig jwtConfig;
public JwtTokenVerifier(JwtConfig jwtConfig) {
super();
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authorizationHeader == null || authorizationHeader.isEmpty() || !authorizationHeader.startsWith(jwtConfig.getTokenPrefix())) {
String requestParam = request.getParameter("token");
if (requestParam != null && !requestParam.isEmpty() && requestParam.startsWith(jwtConfig.getTokenPrefix())) {
authorizationHeader = requestParam;
} else {
filterChain.doFilter(request, response);
return;
}
}
try {
if (jwtConfig.validateJwtToken(authorizationHeader)) {
String username = jwtConfig.getUserNameFromJwtToken(authorizationHeader);
Authentication auth = new UsernamePasswordAuthenticationToken(username, new WebAuthenticationDetailsSource().buildDetails(request), null);
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
e.printStackTrace();
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
}
filterChain.doFilter(request, response);
}
}
在 WebSecurityConfigurerAdapter
扩展中,我看到 ACTUATOR
,但在用户详细信息定义中我看到 ROLE_ACTUATOR
。这是不匹配吗?
感谢@SteveRiesenberg,正如在聊天中所说 “如果您的自定义 JWT 过滤器不处理角色,那就是问题所在。执行身份验证时必须填充角色(权限) ."
因此,由于角色未在过滤器中处理,因此它们未通过安全链。
过滤器的代码编辑如下:
UserDetailsImpl userDetails = (UserDetailsImpl) userDetailsService.loadUserByUsername(username);
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
Authentication auth = new UsernamePasswordAuthenticationToken(username, new WebAuthenticationDetailsSource().buildDetails(request), authorities);
其中权限传递给UsernamePasswordAuthenticationToken
,UserDetailsImpl
是由spring
UserDetails
class的实现