我正在構建一個 springboot 應用程式,目前正在嘗試實作基于權限的授權。在我的 securityConfig 檔案中,基于角色的授權有效,但基于權限的授權失敗。從下面的SecurityConfig 檔案中可以看出,在antMatchers 的hasAnyRole 函式中傳遞一個角色是可行的,但是將權限傳遞給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);
}
}
}
}
uj5u.com熱心網友回復:
In your custom filter you parse "roles" JWT claims only to roles as String, so your SecurityContext doesn't know anything about permissions (authorities).
Instead of this try to utilize your ApplicationUserRole enum .getGrantedAuthorities() method, for example like this:
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);
If "roles" claim cannot be parsed to an array of ApplicationUserRole, then .valueOf() method will throw IllegalArgumentException, and your catch block will convert it to 403 http status response.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/508397.html
