返回

接口放行——从Spring Security入手

后端

前言

在实际项目中,我们经常会遇到需要放行一些接口,使其能匿名访问的业务需求。例如,登录接口、注册接口等,通常是不需要经过身份认证就可以访问的。然而,在Spring Security中,默认情况下所有的接口都需要经过身份认证才能访问。因此,我们需要对Spring Security进行一些配置,以允许某些接口可以匿名访问。

传统放行方式

Spring Security提供了多种放行方式,其中最常见的一种是通过在安全配置类中添加permitAll()方法来放行接口。例如:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/login", "/register")
                .permitAll()
                .anyRequest()
                .authenticated();
    }
}

通过这种方式,我们可以放行/login/register这两个接口,使其可以匿名访问。但是,每当我们需要放行新的接口时,都需要在安全配置类中进行修改。这不仅增加了配置的复杂性,而且也不利于代码的维护。

自定义注解放行

为了解决上述问题,我们可以使用自定义注解来放行接口。通过这种方式,我们可以将接口的放行逻辑与安全配置类分离,从而提高代码的可维护性。

首先,我们需要创建一个自定义注解@Pass,用于标记需要放行的接口。例如:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pass {
}

然后,我们需要在Spring Security的配置类中配置自定义注解@Pass。例如:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/login", "/register")
                .permitAll()
                .antMatchers(HttpMethod.POST, "/login", "/register")
                .access("@passChecker.check(request, authentication)")
                .anyRequest()
                .authenticated();
    }

    @Bean
    public PassChecker passChecker() {
        return new PassChecker();
    }
}

在上面的代码中,我们使用@Bean方法创建了一个PassChecker bean,用于检查请求是否可以通过自定义注解@PassPassChecker类的代码如下:

public class PassChecker {

    public boolean check(HttpServletRequest request, Authentication authentication) {
        // 获取请求的路径
        String path = request.getServletPath();

        // 获取请求的方法
        String method = request.getMethod();

        // 根据请求的路径和方法,判断是否可以通过自定义注解@Pass
        if ("/login".equals(path) && "POST".equals(method)) {
            return true;
        }

        if ("/register".equals(path) && "POST".equals(method)) {
            return true;
        }

        return false;
    }
}

最后,我们需要在需要放行的接口上添加自定义注解@Pass。例如:

@PostMapping("/login")
@Pass
public String login() {
    // ...
}

通过这种方式,我们就可以轻松地放行需要匿名访问的接口。

总结

在本文中,我们介绍了如何在Spring Security项目中使用自定义注解放行接口。通过这种方法,我们可以轻松地放行需要匿名访问的接口,而无需在安全配置类中进行修改。这不仅提高了代码的可维护性,而且也有利于代码的扩展。

示例代码

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/login", "/register")
                .permitAll()
                .antMatchers(HttpMethod.POST, "/login", "/register")
                .access("@passChecker.check(request, authentication)")
                .anyRequest()
                .authenticated();
    }

    @Bean
    public PassChecker passChecker() {
        return new PassChecker();
    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pass {
}

public class PassChecker {

    public boolean check(HttpServletRequest request, Authentication authentication) {
        // 获取请求的路径
        String path = request.getServletPath();

        // 获取请求的方法
        String method = request.getMethod();

        // 根据请求的路径和方法,判断是否可以通过自定义注解@Pass
        if ("/login".equals(path) && "POST".equals(method)) {
            return true;
        }

        if ("/register".equals(path) && "POST".equals(method)) {
            return true;
        }

        return false;
    }
}

@PostMapping("/login")
@Pass
public String login() {
    // ...
}