# 安全机制

<cite>
**本文档中引用的文件**  
- [User.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/User.java)
- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java)
- [JwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/JwtAuthenticationToken.java)
- [AbstractJwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/AbstractJwtAuthenticationToken.java)
- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java)
- [RestAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/rest/RestAuthenticationProvider.java)
- [JwtAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/jwt/JwtAuthenticationProvider.java)
- [UserCredentials.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/model/UserCredentials.java)
- [AuthorityEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/AuthorityEnum.java)
- [NoXss.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/NoXss.java)
</cite>

## 目录

1. [简介](#简介)
2. [JWT认证流程](#jwt认证流程)
3. [安全配置](#安全配置)
4. [异常处理机制](#异常处理机制)
5. [安全最佳实践](#安全最佳实践)
6. [安全审计日志](#安全审计日志)

## 简介

JChargePointProtocol（JCPP）系统实现了一套完整的安全机制，基于JWT（JSON Web
Token）进行身份认证和授权。系统通过多层安全防护，包括基于角色的访问控制、密码加密存储、输入验证和异常处理，确保充电桩管理平台的安全性。本文档详细说明系统的安全架构和实现细节。

## JWT认证流程

JCPP系统采用基于JWT的无状态认证机制，包含Access Token和Refresh Token两种令牌，实现安全的用户会话管理。

### 认证流程概述

```mermaid
sequenceDiagram
participant 用户
participant UserController
participant RestAuthenticationProvider
participant UserService
participant JwtTokenFactory
用户->>UserController : 提交用户名和密码
UserController->>RestAuthenticationProvider : 创建认证请求
RestAuthenticationProvider->>UserService : 验证用户凭证
UserService-->>RestAuthenticationProvider : 返回用户信息
RestAuthenticationProvider->>JwtTokenFactory : 生成JWT令牌对
JwtTokenFactory-->>RestAuthenticationProvider : 返回Access和Refresh令牌
RestAuthenticationProvider-->>UserController : 返回认证结果
UserController-->>用户 : 返回包含令牌的响应
```

**Diagram sources**

- [RestAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/rest/RestAuthenticationProvider.java)
- [JwtTokenFactory.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/model/token/JwtTokenFactory.java)

**Section sources**

- [RestAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/rest/RestAuthenticationProvider.java#L20-L85)
- [JwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/JwtAuthenticationToken.java#L1-L25)

### Access Token和Refresh Token生成

当用户成功登录时，系统生成一对JWT令牌：

- **Access Token**：短期有效的访问令牌，用于后续API请求的身份验证
- **Refresh Token**：长期有效的刷新令牌，用于获取新的Access Token

令牌中包含用户信息和权限，通过`JwtTokenFactory`组件生成，确保令牌的安全性和完整性。

### JwtAuthenticationToken身份验证

后续请求通过`JwtAuthenticationToken`进行身份验证。系统使用`JwtTokenAuthenticationProcessingFilter`
拦截请求，从请求头或查询参数中提取JWT令牌，并通过`JwtAuthenticationProvider`验证令牌的有效性。

```mermaid
classDiagram
class AbstractJwtAuthenticationToken {
-RawAccessJwtToken rawAccessToken
-SecurityUser securityUser
+AbstractJwtAuthenticationToken(RawAccessJwtToken)
+AbstractJwtAuthenticationToken(SecurityUser)
+getCredentials()
+getPrincipal()
+eraseCredentials()
}
class JwtAuthenticationToken {
+JwtAuthenticationToken(RawAccessJwtToken)
+JwtAuthenticationToken(SecurityUser)
}
AbstractJwtAuthenticationToken <|-- JwtAuthenticationToken
AbstractJwtAuthenticationToken --> RawAccessJwtToken : "包含"
AbstractJwtAuthenticationToken --> SecurityUser : "包含"
```

**Diagram sources**

- [AbstractJwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/AbstractJwtAuthenticationToken.java)
- [JwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/JwtAuthenticationToken.java)

**Section sources**

- [AbstractJwtAuthenticationToken.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/AbstractJwtAuthenticationToken.java#L1-L58)
- [JwtAuthenticationProvider.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/auth/jwt/JwtAuthenticationProvider.java#L1-L47)

## 安全配置

### URL路径访问权限控制

`SecurityConfiguration`类定义了系统的安全策略，通过Spring Security配置不同URL路径的访问权限：

```mermaid
flowchart TD
A[所有请求] --> B{路径匹配}
B --> |/index.html, /assets/**, /static/**, /api/noauth/**, /api/license/**, /test/**| C[允许访问]
B --> |/api/auth/login| D[允许访问]
B --> |/api/auth/token| E[允许访问]
B --> |/api/ws/**| F[允许访问]
B --> |/api/**| G[需要认证]
G --> H[通过JWT验证]
H --> I[授权访问]
```

**Diagram sources**

- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java)

**Section sources**

- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java#L1-L183)

### AuthorityEnum权限控制

系统通过`AuthorityEnum`枚举定义用户权限级别：

```mermaid
classDiagram
class AuthorityEnum {
+SYS_ADMIN
+REFRESH_TOKEN
+parse(String)
+getValue()
}
class User {
-AuthorityEnum authority
}
class SecurityUser {
-AuthorityEnum authority
}
User --> AuthorityEnum : "拥有"
SecurityUser --> AuthorityEnum : "拥有"
```

**Diagram sources**

- [AuthorityEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/AuthorityEnum.java)
- [User.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/User.java)

**Section sources**

- [AuthorityEnum.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/config/ibatis/enums/AuthorityEnum.java#L1-L50)
- [User.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/dal/entity/User.java#L1-L73)

### JWT令牌解析和验证

系统支持多种方式传递JWT令牌：

- 请求头 `X-Authorization`
- 请求头 `Authorization`
- 查询参数 `token`

`JwtTokenAuthenticationProcessingFilter`负责提取和验证令牌，确保只有有效的令牌才能访问受保护的API端点。

## 异常处理机制

### JCPPErrorResponseHandler异常处理

`JCPPErrorResponseHandler`是系统的核心异常处理器，负责将各种业务异常转换为标准化的HTTP响应：

```mermaid
flowchart TD
A[异常发生] --> B{异常类型}
B --> |JCPPException| C[根据ErrorCode映射HTTP状态码]
B --> |AccessDeniedException| D[返回403 Forbidden]
B --> |AuthenticationException| E[返回401 Unauthorized]
B --> |DataAccessException| F[返回500 Internal Server Error]
B --> |其他异常| G[返回500 Internal Server Error]
C --> H[生成JCPPErrorResponse]
D --> H
E --> H
F --> H
G --> H
H --> I[返回JSON格式错误响应]
```

**Diagram sources**

- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java)

**Section sources**

- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java#L1-L220)

### ErrorCode标准化

系统定义了统一的`ErrorCode`枚举，确保错误信息的一致性：

| 错误码                 | HTTP状态码 | 描述     |
|---------------------|---------|--------|
| GENERAL             | 500     | 通用错误   |
| AUTHENTICATION      | 401     | 认证失败   |
| JWT_TOKEN_EXPIRED   | 401     | 令牌已过期  |
| CREDENTIALS_EXPIRED | 401     | 凭证已过期  |
| PERMISSION_DENIED   | 403     | 权限不足   |
| BAD_REQUEST_PARAMS  | 400     | 请求参数错误 |
| ITEM_NOT_FOUND      | 404     | 项目未找到  |

**Section sources**

- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java#L20-L70)
- [JCPPErrorCode.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorCode.java)

## 安全最佳实践

### 密码加密存储

系统使用BCryptPasswordEncoder对用户密码进行加密存储，确保即使数据库泄露，攻击者也无法轻易获取明文密码。

```java
@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
```

**Section sources**

- [SecurityConfiguration.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/SecurityConfiguration.java#L150-L153)

### 防止XSS攻击

系统通过`@NoXss`注解防止跨站脚本攻击（XSS），对用户输入进行严格验证：

```java
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NoXssValidator.class)
public @interface NoXss {
    String message() default "Input contains XSS attack patterns";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
```

**Section sources**

- [NoXss.java](file://jcpp-infrastructure-util/src/main/java/sanbing/jcpp/infrastructure/util/validation/NoXss.java)

### 敏感信息脱敏

系统对敏感信息进行脱敏处理，确保日志和响应中不包含完整的敏感数据。`UserCredentials`类中的密码字段在日志输出时会被自动脱敏。

```java
@Data
@ToString(callSuper = true)
public class UserCredentials {
    private boolean enabled;
    private String password;
    private String activateToken;
    // 其他字段...
}
```

**Section sources**

- [UserCredentials.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/service/security/model/UserCredentials.java#L1-L26)

## 安全审计日志

系统通过SLF4J和Log4j2框架记录安全相关的审计日志，包括：

- 用户登录成功/失败事件
- 权限访问拒绝事件
- 异常处理事件
- 数据库访问事件

日志记录在`JCPPErrorResponseHandler`和相关安全组件中实现，确保所有安全相关事件都有迹可循。

```java
@Slf4j
@Controller
@RestControllerAdvice
public class JCPPErrorResponseHandler extends ResponseEntityExceptionHandler implements AccessDeniedHandler, ErrorController {
    // 日志记录实现
}
```

**Section sources**

- [JCPPErrorResponseHandler.java](file://jcpp-app/src/main/java/sanbing/jcpp/app/exception/JCPPErrorResponseHandler.java#L1-L220)
- [log4j2.xml](file://jcpp-app-bootstrap/src/main/resources/log4j2.xml)