繁体   English   中英

如何让我的 spring 安全自定义角色权限感知?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM