[英]How can I make my spring security custom roles permission aware?
我正在构建一个 springboot 应用程序,目前正在尝试实现基于权限的授权。 在我的 securityConfig 文件中,基于角色的授权有效,但基于权限的授权失败。 从下面的SecurityConfig 文件中可以看出,在antMatchers 中传递hasAnyRole function 中的角色是可行的,但是将权限传递给hasAnyAuthority 不起作用,即它没有授权。
这是我的安全配置文件
@Override
protected void configure(HttpSecurity http) throws Exception {
/*
* Setting custom login endpoint
* */
CustomAuthenticationFilter customAuthenticationFilter = new CustomAuthenticationFilter(authenticationManagerBean());
customAuthenticationFilter.setFilterProcessesUrl("/api/login");
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.antMatchers("/api/login/**", "/api/token/refresh/**").permitAll()
.antMatchers("/api/users/save/**").permitAll()
.antMatchers(GET, "/api/users/**").hasAnyAuthority(CAN_ADD_MEMBER_TO_CHAMA.getPermission())
.antMatchers(GET, "/api/users/**").hasAnyRole(PLATFORM_SUPER_ADMIN.name())
.anyRequest()
.authenticated()
.and();
http.addFilter(customAuthenticationFilter);
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
}
角色
public enum ApplicationUserRole {
PLATFORM_SUPER_ADMIN(
Sets.newHashSet(
CAN_CREATE_CHAMA, CAN_DELETE_CHAMA,
CAN_UPDATE_CHAMA, CAN_INVITE_NEW_USER)),
PLATFORM_USER(Sets.newHashSet(CAN_CREATE_CHAMA)),
CHAMA_MEMBER(Sets.newHashSet(CAN_MAKE_CONTRIBUTION, CAN_INVITE_NEW_USER));
private final Set<ApplicationUserPermission> permissions;
ApplicationUserRole(Set<ApplicationUserPermission> permissions) {
this.permissions = permissions;
}
public Set<ApplicationUserPermission> getPermissions() {
return permissions;
}
public Set<SimpleGrantedAuthority> getGrantedAuthorities() {
Set<SimpleGrantedAuthority> permissions = getPermissions().stream()
.map(permission -> new SimpleGrantedAuthority(permission.getPermission()))
.collect(Collectors.toSet());
permissions.add(new SimpleGrantedAuthority("ROLE_" + this.name()));
return permissions;
}
}
权限
package com.chama.chamaservice.config;
public enum ApplicationUserPermission {
CAN_CREATE_CHAMA("CAN_CREATE_CHAMA"),
CAN_DELETE_CHAMA("CAN_DELETE_CHAMA"),
CAN_UPDATE_CHAMA("CAN_UPDATE_CHAMA"),
private final String permission;
ApplicationUserPermission(String permission) {
this.permission = permission;
}
public String getPermission() {
return permission;
}
}
自定义授权过滤器
public class CustomAuthorizationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (request.getServletPath().equals("/api/login") || request.getServletPath().equals("/api/refresh/token")) {
filterChain.doFilter(request, response);
} else {
// Generate new access token from refresh token
String authorizationHeader = request.getHeader(AUTHORIZATION);
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
try {
String token = authorizationHeader.substring("Bearer ".length());
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT decodedJWT = verifier.verify(token);
String phoneNumber = decodedJWT.getSubject();
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
stream(roles).forEach(role -> {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); // Populate ROLES
});
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phoneNumber, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
} catch (Exception e) {
log.error("Error logging in: {}", e.getMessage());
response.setHeader("error", e.getMessage());
response.setStatus(FORBIDDEN.value());
Map<String, String> error = new HashMap<>();
error.put("message", e.getMessage());
response.setContentType(APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getOutputStream(), error);
}
} else {
filterChain.doFilter(request, response);
}
}
}
}
在您的自定义过滤器中,您解析“角色” JWT 仅将角色声明为String
,因此您的SecurityContext
对权限(权限)一无所知。
而不是这个尝试使用您的ApplicationUserRole
枚举.getGrantedAuthorities()
方法,例如:
String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
Collection<SimpleGrantedAuthority> authorities = Arrays.stream(roles)
.map(ApplicationUserRole::valueOf) // <- parsing every String to ApplicationUserRole
.map(ApplicationUserRole::getGrantedAuthorities) // <- converting every ApplicationUserRole to a set of GrantedAuthority
.flatMap(Collection::stream) // <- converting stream of sets to a stream of GrantedAuthority
.collect(Collectors.toList());
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(phoneNumber, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
filterChain.doFilter(request, response);
如果“角色”声明无法解析为ApplicationUserRole
数组,则.valueOf()
方法将抛出IllegalArgumentException
,并且您的catch
块会将其转换为 403 http 状态响应。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.