返回
接口放行——从Spring Security入手
后端
2023-12-21 09:21:54
前言
在实际项目中,我们经常会遇到需要放行一些接口,使其能匿名访问的业务需求。例如,登录接口、注册接口等,通常是不需要经过身份认证就可以访问的。然而,在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,用于检查请求是否可以通过自定义注解@Pass
。PassChecker
类的代码如下:
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() {
// ...
}