Spring Security OAuth2(4) judges dynamic permissions based on request URI

GitHub address

Code cloud address

Generally, we control permissions through the @PreAuthorize("hasRole('ROLE_USER')") annotation and configuring permission requirements in HttpSecurity. Here, we control access based on the URI of the request, and we can use annotations to control access.

Create a new resource project and configure resource services. First, customize a permission authentication MySecurityAccessDecisionManager to inherit the AccessDecisionManager interface, rewrite the decide method, and copy the remaining two methods of the default permission authentication AbstractAccessDecisionManager (the focus of implementing annotation control). The permissions that the user has have been customized in the authentication server.

/**
 * @Description 自定义权限认证,获取url判断是否有权限
 * @Author wwz
 * @Date 2019/08/01
 * @Param
 * @Return
 */
@Component
public class MySecurityAccessDecisionManager implements AccessDecisionManager {

    private List<AccessDecisionVoter<? extends Object>> decisionVoters;

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        String requestUrl = ((FilterInvocation) object).getRequest().getMethod() + ((FilterInvocation) object).getRequest().getRequestURI();
//        System.out.println("requestUrl>>" + requestUrl);

        // 当前用户所具有的权限
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
//        System.out.println("authorities=" + authorities);
        for (GrantedAuthority grantedAuthority : authorities) {
            if (grantedAuthority.getAuthority().equals(requestUrl)) {
                return;
            }
            if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) {
                return;
            }

        }
        throw new AccessDeniedException("无访问权限");
    }

    /**
     * 复制默认方法,使得@PreAuthorize("hasRole('ROLE_ADMIN')") 可用
     */
    @Override
    public boolean supports(ConfigAttribute attribute) {
        for (AccessDecisionVoter voter : this.decisionVoters) {
            if (voter.supports(attribute)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        for (AccessDecisionVoter voter : this.decisionVoters) {
            if (!voter.supports(clazz)) {
                return false;
            }
        }
        return true;
    }
}

Override and inject in httpSecurity of resource service configuration:

/**
 * @Description 资源认证
 * @Author wwz
 * @Date 2019/08/01
 * @Param
 * @Return
 */
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)   // 启用注解权限配置
public class MySecurityResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private RedisConnectionFactory connectionFactory;

    @Bean
    public TokenStore tokenStore() {
        RedisTokenStore redis = new RedisTokenStore(connectionFactory);
        return redis;
    }

    @Resource
    private MyAccessDeniedHandler accessDeniedHandler; // 无权访问处理器

    @Resource
    private MyTokenExceptionEntryPoint tokenExceptionEntryPoint; // token失效处理器

    @Resource
    private MySecurityAccessDecisionManager accessDecisionManager; //权限判断

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 另外,如果不设置,那么在通过浏览器访问被保护的任何资源时,每次是不同的SessionID,并且将每次请求的历史都记录在OAuth2Authentication的details的中
                .and()
                .authorizeRequests().antMatchers("/actuator/health").permitAll().anyRequest().authenticated()  // httpSecurity 放过健康检查,其他都需要验证  设置了.anyRequest().authenticated()才回进入自定义的权限判断
                .and()
                .requestMatchers().antMatchers("/auth/**") // .requestMatchers().antMatchers(...) OAuth2设置对资源的保护如果是用 /**的话 会把上面的也拦截掉
                .and()
                .authorizeRequests()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {       // 重写做权限判断
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setAccessDecisionManager(accessDecisionManager);      // 权限判断
                        return o;
                    }
                })
                .and()
                .httpBasic();

        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(tokenExceptionEntryPoint); // token失效处理器
        resources.resourceId("manager"); // 设置资源id  通过client的 resource_ids 来判断是否具有资源权限  资源不存在会报Invalid token does not contain resource id (manager)
    }
}

At the break point of MySecurityAccessDecisionManager, it can be found that all requests go here for permission judgment. According to the combination of permissions in the authentication server, the request matching the uri is combined with the annotation permission on the method to judge whether or not to have access. The principle is that all pass is passed. , otherwise no right.

SpringSecurityOAuth2(4) Dynamic permission judgment based on request URI (supplement)Next article

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324147785&siteId=291194637