Spring Security OAuth2 Judges Dynamic Permissions Based on Request URI

Posted by bonekrusher on Sat, 12 Oct 2019 21:21:03 +0200

GitHub address

Code cloud address

Usually we control permissions by @PreAuthorize("hasRole('ROLE_USER')) annotation, and configuring permission requirements in HttpSecurity. Here, we control access rights based on the requested URI, and we can use annotations to control access rights.

Create a new resource project to allocate resources and services. First, we customize a privilege authentication MySecurity Access Decision Manager to inherit the Access Decision Manager interface and override the decision method. And copy the remaining two methods of default permission validation for AbstractAccessDecision Manager (the focus of annotation control). The user's privileges have been customized in the authentication server.

/**
 * @Description Customize permission authentication, get url to determine whether permission exists
 * @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);

        // Permissions of the current user
        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("No access rights");
    }

    /**
     * Copy the default method to make @PreAuthorize("hasRole('ROLE_ADMIN')) available
     */
    @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;
    }
}

Rewrite and inject in HTTP security of resource service configuration:

/**
 * @Description Resource authentication
 * @Author wwz
 * @Date 2019/08/01
 * @Param
 * @Return
 */
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)   // Enable Annotation Permission Configuration
public class MySecurityResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private RedisConnectionFactory connectionFactory;

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

    @Resource
    private MyAccessDeniedHandler accessDeniedHandler; // No access to processor

    @Resource
    private MyTokenExceptionEntryPoint tokenExceptionEntryPoint; // token failure processor

    @Resource
    private MySecurityAccessDecisionManager accessDecisionManager; //Authority judgement

    @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) // In addition, if not set, then when accessing any protected resource through a browser, each time it is a different Session ID, and the history of each request is recorded in OAuth 2Authentication details.
                .and()
                .authorizeRequests().antMatchers("/actuator/health").permitAll().anyRequest().authenticated()  // Http Security passes health checks and all other validation settings need to be set. anyRequest().authenticated() before entering the custom permission judgment.
                .and()
                .requestMatchers().antMatchers("/auth/**") // The. requestMatchers().antMatchers(...) OAuth2 settings protect resources and intercept them with /**
                .and()
                .authorizeRequests()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {       // Rewrite for permission judgment
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setAccessDecisionManager(accessDecisionManager);      // Authority judgement
                        return o;
                    }
                })
                .and()
                .httpBasic();

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

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(tokenExceptionEntryPoint); // token failure processor
        resources.resourceId("manager"); // Setting the resource id to determine whether a resource with resource privileges does not exist will report Invalid token does not contain resource id (manager)
    }
}

At the interruption point of MySecurity Access Decision Manager, it can be found that all requests go here to judge whether they have the right to access. According to the combination of privileges in the authentication server, matching uri requests with annotation privileges in the method can be used to judge whether they have the right to access. The principle is to go beyond the limit, otherwise they have no right.

Topics: Programming Redis Attribute github Session