基于Spring Boot 3.3.4,详细说明Spring Security 6.3.3的使用
摘要
【Spring Security】基于SpringBoot3.3.4版本①整合JWT的使用教程
在这篇文章中,详细演示了使用最新版Spring Boot
,完成一个微服务开发,并使用Spring Security
组件完成登录认证,同时整合了JWT
,使用的RSA
公私钥签名、验签。
接下来继续讲解下一个业务场景:一个真实场景的微服务,难免会有一些请求Path
不需要任何鉴权,比如某些仅对内的API
、允许匿名访问的资源等等。那么,如何在Spring Security
体系中,把这些免鉴权的Path
绕过认证呢?并且可以灵活的配置呢?
接下来让我就带着你一起解决这个业务场景中的问题吧!
本地开发环境说明
开发用到的主要框架、工具版本如下
开发依赖 | 版本 |
---|---|
Spring Boot | 3.3.4 |
Spring Security | 6.3.3 |
JDK | 21 |
IntelliJ IDEA | 2024.2.3 |
【Spring Security】基于SpringBoot3.3.4版本①整合JWT的使用教程 建议大家先阅读这篇文章,本文是对这篇文章的进一步扩展。
SecurityFilterChain介绍
我们在构建SecurityFilterChain
的时候,可以通过authorizeHttpRequestsCustomizer.requestMatchers(HttpMethod.POST, "/login/common").permitAll()
这种方式告诉Spring Security
,对于/login/common
这个path
不需要鉴权,代码如下
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
Wen3SecurityProperties wen3SecurityProperties = wen3SecurityProperties();
http.authorizeHttpRequests(authorizeHttpRequestsCustomizer -> {
authorizeHttpRequestsCustomizer
.requestMatchers(HttpMethod.POST, "/login/common").permitAll()
.requestMatchers(HttpMethod.GET, "/login/verify").permitAll()
.requestMatchers(new AntPathRequestMatcher("/**/test")).permitAll()
.anyRequest().authenticated();
});
// token校验过滤器
http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
// 禁用表单提交 取消默认的登录页面
http.formLogin(AbstractHttpConfigurer::disable);
// 禁用注销 取消默认的登出页面
http.logout(AbstractHttpConfigurer::disable);
// 禁用csrf功能,方便使用curl或postman测试
http.csrf(AbstractHttpConfigurer::disable);
//将自己的认证服务加入
http.authenticationProvider(authenticatorProvider());
//禁用session,因为使用token
http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
//禁用http基本认证,因为传输数据用的post,且请求体为JSON
http.httpBasic(AbstractHttpConfigurer::disable);
return http.build();
}
这种方式有一个明细的缺点,那就是硬编码写死的,因此接下来我们把免鉴权的Path放到配置文件中
application.yml
修改application.yml
文件,增加如下配置
wen3:
security:
ignored-paths: /ignore/**
Wen3SecurityProperties.java
新增配置类Wen3SecurityProperties
package com.wen3.security.springsecurity.autoconfigure;
import lombok.*;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;
/**
* @author: tangheng
*/
@Data
@Accessors(chain = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@ConfigurationProperties(prefix = "wen3.security")
public class Wen3SecurityProperties {
/**免鉴权Path*/
List<String> ignoredPaths;
}
修改DemoWen3Security
增加如下配置
@Bean
Wen3SecurityProperties wen3SecurityProperties() {
return new Wen3SecurityProperties();
}
修改SecurityFilterChain
判断wen3SecurityProperties.getIgnoredPaths()
不为空,则添加到authorizeHttpRequestsCustomizer
中
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
Wen3SecurityProperties wen3SecurityProperties = wen3SecurityProperties();
http.authorizeHttpRequests(authorizeHttpRequestsCustomizer -> {
if(!CollectionUtils.isEmpty(wen3SecurityProperties.getIgnoredPaths())) {
authorizeHttpRequestsCustomizer.requestMatchers(wen3SecurityProperties.getIgnoredPaths().toArray(String[]::new)).permitAll();
}
authorizeHttpRequestsCustomizer
.requestMatchers(HttpMethod.POST, "/login/common").permitAll()
.requestMatchers(HttpMethod.GET, "/login/verify").permitAll()
.requestMatchers(new AntPathRequestMatcher("/**/test")).permitAll()
.anyRequest().authenticated();
});
// token校验过滤器
http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
// 禁用表单提交 取消默认的登录页面
http.formLogin(AbstractHttpConfigurer::disable);
// 禁用注销 取消默认的登出页面
http.logout(AbstractHttpConfigurer::disable);
// 禁用csrf功能,方便使用curl或postman测试
http.csrf(AbstractHttpConfigurer::disable);
//将自己的认证服务加入
http.authenticationProvider(authenticatorProvider());
//禁用session,因为使用token
http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
//禁用http基本认证,因为传输数据用的post,且请求体为JSON
http.httpBasic(AbstractHttpConfigurer::disable);
return http.build();
}
IgnoredPathController.java
增加免鉴权API
package com.wen3.security.springsecurity.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: tangheng
*/
@Slf4j
@RequestMapping("/ignore")
@RestController
public class IgnoredPathController {
@RequestMapping("/hello")
public String hello() {
return "hello, world";
}
}
IgnoredPathController2.java
增加免鉴权IgnoredPathController2
,方便用于测试对比
package com.wen3.security.springsecurity.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author: tangheng
*/
@Slf4j
@RequestMapping("/ignore2")
@RestController
public class IgnoredPathController2 {
@RequestMapping("/hello")
public String hello() {
return "hello, world";
}
}
启动工程
启动日志如下
测试
测试免鉴权Path
curl -ik -H "Content-Type: application/json" -XGET --url "http://localhost:8081/ignore/hello"
接口响应
HTTP/1.1 200
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: text/plain;charset=UTF-8
Content-Length: 12
Date: Thu, 03 Oct 2024 07:04:24 GMT
hello, world
测试鉴权Path
curl -ik -H "Content-Type: application/json" -XGET --url "http://localhost:8081/ignore2/hello"
接口响应
HTTP/1.1 403
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Thu, 03 Oct 2024 07:05:09 GMT
总结
- 本文演示了如何通过配置文件配置免鉴权
API
- 免鉴权的配置既然可以配置在配置文件中,那么就可以根据需要放到配置中心,比如
Nacos
、Eureka
等