文章目录
-
- 前言
- 设计思路
- SDK实现步骤
-
- [1. 创建SDK Maven项目(sdk目录)](#1. 创建SDK Maven项目(sdk目录))
- [2. 实现配置类](#2. 实现配置类)
- [3. 实现认证逻辑](#3. 实现认证逻辑)
- [4. 实现拦截器](#4. 实现拦截器)
- [5. 实现自动配置](#5. 实现自动配置)
- [6. 创建spring.factories文件](#6. 创建spring.factories文件)
- 使用方集成步骤
-
- [1. 引入SDK依赖](#1. 引入SDK依赖)
- [2. 配置Application属性](#2. 配置Application属性)
- [3. 创建测试接口](#3. 创建测试接口)
- [4. 测试接口访问](#4. 测试接口访问)
- SDK扩展功能
- 总结
前言
Spring Boot作为当前最流行的Java开发框架之一,其Starter机制为开发者提供了极大的便利,使得集成各种功能变得更加简单。为了帮助开发者快速实现基于AppID和AppSecret的应用认证功能,我们设计并实现了这个认证SDK。该SDK遵循Spring Boot Starter的最佳实践,可以无缝集成到Spring Boot应用中,提供开箱即用的Basic认证功能。

设计思路
创建一个Spring Boot Starter风格的SDK,它会:
1.自动配置认证所需的组件
2.提供简单的配置方式管理多个AppID/AppSecret
3.通过拦截器自动保护指定接口
4.提供统一的错误响应处理
下面是整个认证流程的示意图:
SDK实现步骤
1. 创建SDK Maven项目(sdk目录)
创建sdk/pom.xml文件:
bash
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>java-basic-sdk</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>java-basic-sdk</name>
<description>java-basic-sdk</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. 实现配置类
创建配置属性类AppAuthProperties.java:
bash
/**
* AppAuthProperties
* @author senfel
* @version 1.0
* @date 2025/9/12 16:17
*/
@ConfigurationProperties(prefix = "app.auth")
public class AppAuthProperties {
/**
* 是否启用App认证
*/
private boolean enabled = true;
/**
* 需要认证的路径模式(默认保护/test接口)
*/
private String[] includePatterns = new String[]{"/test/**"};
/**
* 排除的路径模式
*/
private String[] excludePatterns = new String[]{};
/**
* 存储有效的AppID和AppSecret键值对
*/
private Map<String, String> clients = new HashMap<>();
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String[] getIncludePatterns() {
return includePatterns;
}
public void setIncludePatterns(String[] includePatterns) {
this.includePatterns = includePatterns;
}
public String[] getExcludePatterns() {
return excludePatterns;
}
public void setExcludePatterns(String[] excludePatterns) {
this.excludePatterns = excludePatterns;
}
public Map<String, String> getClients() {
return clients;
}
public void setClients(Map<String, String> clients) {
this.clients = clients;
}
}
3. 实现认证逻辑
创建认证服务类AppAuthService.java:
bash
/**
* AppAuthService
* @author senfel
* @version 1.0
* @date 2025/9/12 16:19
*/
public class AppAuthService {
private final AppAuthProperties properties;
public AppAuthService(AppAuthProperties properties) {
this.properties = properties;
}
/**
* 验证AppID和AppSecret是否有效
*/
public boolean validateCredentials(String appId, String appSecret) {
if (!StringUtils.hasText(appId) || !StringUtils.hasText(appSecret)) {
return false;
}
// 检查配置中是否存在该AppID且AppSecret匹配
return properties.getClients().containsKey(appId) &&
properties.getClients().get(appId).equals(appSecret);
}
/**
* 从HTTP Basic认证头中提取凭证
*/
public String[] extractCredentials(String authorizationHeader) {
if (!StringUtils.hasText(authorizationHeader) ||
!authorizationHeader.startsWith("Basic ")) {
return null;
}
try {
String base64Credentials = authorizationHeader.substring(6);
String credentials = new String(Base64.getDecoder().decode(base64Credentials));
return credentials.split(":", 2);
} catch (Exception e) {
return null;
}
}
}
4. 实现拦截器
创建认证拦截器AppAuthInterceptor.java:
bash
/**
* AppAuthInterceptor
* @author senfel
* @version 1.0
* @date 2025/9/12 16:20
*/
public class AppAuthInterceptor implements HandlerInterceptor {
private final AppAuthService appAuthService;
public AppAuthInterceptor(AppAuthService appAuthService) {
this.appAuthService = appAuthService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 从请求头中获取Authorization信息
String authorizationHeader = request.getHeader("Authorization");
// 提取AppID和AppSecret
String[] credentials = appAuthService.extractCredentials(authorizationHeader);
if (credentials == null || credentials.length != 2) {
sendErrorResponse(response, "缺少有效的Authorization请求头,请使用Basic认证格式");
return false;
}
String appId = credentials[0];
String appSecret = credentials[1];
// 验证凭证
if (!appAuthService.validateCredentials(appId, appSecret)) {
sendErrorResponse(response, "无效的AppID或AppSecret");
return false;
}
return true;
}
private void sendErrorResponse(HttpServletResponse response, String message)
throws Exception {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\": 401, \"message\": \"" + message + "\"}");
}
}
5. 实现自动配置
创建自动配置类AppAuthAutoConfiguration.java:
bash
/**
* AppAuthAutoConfiguration
* @author senfel
* @version 1.0
* @date 2025/9/12 16:22
*/
@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(AppAuthProperties.class)
@ConditionalOnProperty(prefix = "app.auth", name = "enabled", havingValue = "true", matchIfMissing = true)
public class AppAuthAutoConfiguration implements WebMvcConfigurer {
private final AppAuthProperties properties;
public AppAuthAutoConfiguration(AppAuthProperties properties) {
this.properties = properties;
}
@Bean
public AppAuthService appAuthService() {
return new AppAuthService(properties);
}
@Bean
public AppAuthInterceptor appAuthInterceptor(AppAuthService appAuthService) {
return new AppAuthInterceptor(appAuthService);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(appAuthInterceptor(appAuthService()))
.addPathPatterns(properties.getIncludePatterns())
.excludePathPatterns(properties.getExcludePatterns());
}
}
6. 创建spring.factories文件
创建sdk/src/main/resources/META-INF/spring.factories文件:
bash
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.javabasicsdk.config.AppAuthAutoConfiguration
使用方集成步骤
1. 引入SDK依赖
在使用方的项目中添加SDK依赖:
bash
<!--java-basic-sdk-->
<dependency>
<groupId>com.example</groupId>
<artifactId>java-basic-sdk</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
2. 配置Application属性
在使用方的application.yml中配置允许访问的AppID和AppSecret:
bash
# App认证配置
app:
auth:
enabled: true
include-patterns:
- /test/**
# 配置允许访问的AppID和AppSecret
clients:
appid1: "appsecret1"
3. 创建测试接口
创建测试ControllerTestBasicController.java:
bash
/**
* TestController
* @author senfel
* @version 1.0
* @date 2025/9/12 16:33
*/
@RestController
@RequestMapping("/test")
public class TestBasicController {
@GetMapping
public String test() {
return "认证成功,可以访问此接口";
}
@GetMapping("/sub")
public String testSub() {
return "认证成功,可以访问子接口";
}
}
4. 测试接口访问
不带basic请求头,会提示认证失败:
带错误的appId/appSecret,会提示验证失败:
正确的认证信息可以访问:
SDK扩展功能
如果想进一步增强SDK的功能,可以考虑:
1.添加日志记录:记录认证成功和失败的请求
2.限流功能:为每个AppID添加请求频率限制
3.动态配置:支持从数据库或配置中心动态加载AppID/AppSecret
4.管理接口:提供管理接口用于动态添加/删除AppID和AppSecret
5.多种认证方式:除了Basic认证,支持自定义请求头等方式
总结
通过以上实现,创建一个Spring Boot Starter风格的AppID/AppSecret认证SDK,使用方只需:
1.引入SDK依赖
2.在application.yml中配置允许访问的AppID和AppSecret
3.创建需要保护的接口(如/test)
SDK会自动拦截配置的接口路径,验证请求中的AppID和AppSecret,只有凭证有效的请求才能访问受保护的接口。这种设计提供了开箱即用的体验,同时保持了足够的灵活性,可以通过配置调整保护的范围和允许的凭证。