Master Spring Security 5.7: Configure Without WebSecurityConfigurerAdapter

This guide walks you through upgrading to Spring Boot 2.7.0 and Spring Security 5.7.1, showing the deprecated WebSecurityConfigurerAdapter removal, the new SecurityFilterChain approach, and advanced dynamic permission techniques with complete code examples.

macrozheng
macrozheng
macrozheng
Master Spring Security 5.7: Configure Without WebSecurityConfigurerAdapter

Spring Boot 2.7.0 and Spring Security 5.7.1 were recently released, deprecating the classic WebSecurityConfigurerAdapter. This article demonstrates the new Spring Security configuration style and how to implement dynamic permission control.

Basic Usage

First, update the pom.xml to use Spring Boot version 2.7.0:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

Old Approach

Before Spring Boot 2.7.0, you needed a configuration class extending WebSecurityConfigurerAdapter and overriding three methods:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class OldSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UmsAdminService adminService;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // configure HttpSecurity
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
            .passwordEncoder(passwordEncoder());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

In Spring Boot 2.7.0, WebSecurityConfigurerAdapter is deprecated, indicating Spring Security is moving away from this pattern.

New Approach

The new method no longer extends WebSecurityConfigurerAdapter. Instead, declare a configuration class and define a SecurityFilterChain bean, moving the HttpSecurity configuration into that method:

@Configuration
public class SecurityConfig {
    @Bean
    SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        // configure HttpSecurity
        return httpSecurity.build();
    }
}

This approach is concise and avoids inheritance.

Advanced Usage

After upgrading, you can also implement dynamic permission control.

Method‑Based Dynamic Permissions

Enable method security with @EnableGlobalMethodSecurity on the configuration class.

Use @PreAuthorize on controller methods to specify required authorities.

@Controller
@RequestMapping("/product")
public class PmsProductController {
    @Autowired
    private PmsProductService productService;

    @ApiOperation("Create product")
    @PostMapping("/create")
    @ResponseBody
    @PreAuthorize("hasAuthority('pms:product:create')")
    public CommonResult create(@RequestBody PmsProductParam productParam) {
        int count = productService.create(productParam);
        return count > 0 ? CommonResult.success(count) : CommonResult.failed();
    }
}

Path‑Based Dynamic Permissions

Implement a filter that checks the request path against dynamically loaded permission data.

public class DynamicSecurityFilter extends AbstractSecurityInterceptor implements Filter {
    @Autowired
    private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;
    @Autowired
    private IgnoreUrlsConfig ignoreUrlsConfig;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        FilterInvocation fi = new FilterInvocation(servletRequest, servletResponse, filterChain);
        // Allow OPTIONS requests
        if (request.getMethod().equals(HttpMethod.OPTIONS.toString())) {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
            return;
        }
        // Allow whitelisted URLs
        PathMatcher pathMatcher = new AntPathMatcher();
        for (String path : ignoreUrlsConfig.getUrls()) {
            if (pathMatcher.match(path, request.getRequestURI())) {
                fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
                return;
            }
        }
        // Perform access decision
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }
    // other required methods omitted for brevity
}

The filter relies on a DynamicSecurityMetadataSource that loads permission mappings from a custom service.

public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    private static Map<String, ConfigAttribute> configAttributeMap = null;
    @Autowired
    private DynamicSecurityService dynamicSecurityService;

    @PostConstruct
    public void loadDataSource() {
        configAttributeMap = dynamicSecurityService.loadDataSource();
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        if (configAttributeMap == null) this.loadDataSource();
        String url = ((FilterInvocation) object).getRequestUrl();
        String path = URLUtil.getPath(url);
        PathMatcher pathMatcher = new AntPathMatcher();
        List<ConfigAttribute> configAttributes = new ArrayList<>();
        for (String pattern : configAttributeMap.keySet()) {
            if (pathMatcher.match(pattern, path)) {
                configAttributes.add(configAttributeMap.get(pattern));
            }
        }
        return configAttributes;
    }
    // other methods omitted for brevity
}

The DynamicSecurityService supplies the permission map, typically loaded from the database.

public interface DynamicSecurityService {
    /** Load resource patterns and corresponding ConfigAttributes */
    Map<String, ConfigAttribute> loadDataSource();
}

Finally, register the dynamic filter in the security configuration:

@Configuration
public class SecurityConfig {
    @Autowired
    private DynamicSecurityService dynamicSecurityService;
    @Autowired
    private DynamicSecurityFilter dynamicSecurityFilter;

    @Bean
    SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        // other HttpSecurity configurations
        if (dynamicSecurityService != null) {
            httpSecurity.addFilterBefore(dynamicSecurityFilter, FilterSecurityInterceptor.class);
        }
        return httpSecurity.build();
    }
}

Effect Test

Start the mall-tiny-security project and log in with an account that only has permission for /brand/listAll. Access the Swagger UI at http://localhost:8088/swagger-ui/.

Insert the returned token into Swagger's authentication header.

Requests to authorized endpoints return data; unauthorized requests return an access‑denied message.

Conclusion

The new Spring Security configuration is elegant and simple, while still offering good compatibility with older code. Mature frameworks tend to keep backward compatibility during upgrades, allowing developers to adopt the new style gradually.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring Bootspring-security
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.