# NestJS 认证处理指南

## 认证架构对比

### 1. PHP ThinkPHP (传统方式)
```php
// 通过中间件全局处理
class AdminCheckToken {
    public function handle(Request $request, Closure $next) {
        // 检查token，某些路由可以跳过
    }
}
```

### 2. Java Spring Boot (注解方式)
```java
@RestController
public class AuthController {
    @SaCheckLogin  // 需要登录
    @GetMapping("/user/info")
    public UserInfo getUserInfo() {}
    
    @SaNotCheckLogin  // 免登录
    @PostMapping("/login")
    public LoginResult login() {}
}
```

### 3. NestJS (装饰器方式) - 更像Java
```typescript
@Controller('adminapi/auth')
export class AuthController {
    @Public()  // 免登录
    @Post('login')
    async login() {}
    
    @Get('user/info')  // 需要登录（默认）
    async getUserInfo() {}
}
```

## NestJS 认证处理方式

### 核心原则
1. **默认需要登录** - 所有接口默认需要认证
2. **@Public()装饰器** - 标记免登录接口
3. **全局守卫** - 统一处理认证逻辑

### 实现方式

#### 1. 全局守卫配置
```typescript
// app.module.ts
@Module({
  providers: [
    { provide: APP_GUARD, useClass: GlobalAuthGuard },
  ],
})
export class AppModule {}
```

#### 2. 全局守卫实现
```typescript
// GlobalAuthGuard.ts
@Injectable()
export class GlobalAuthGuard implements CanActivate {
  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 检查是否有 @Public() 装饰器
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    if (isPublic) {
      return true; // 免登录接口直接通过
    }

    // 需要认证的接口使用JWT认证
    return this.jwtAuthGuard.canActivate(context);
  }
}
```

#### 3. 免登录装饰器
```typescript
// public.decorator.ts
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
```

### 接口分类

#### 1. 免登录接口 (使用 @Public())
- **登录相关**: `/adminapi/login/*`
- **验证码相关**: `/adminapi/captcha/*`
- **公开配置**: `/api/sys/*` (前台公开接口)
- **管理端公开**: `/adminapi/sys/web/*` (管理端公开接口)

#### 2. 需要登录接口 (默认)
- **用户管理**: `/adminapi/auth/*`
- **系统管理**: `/adminapi/sys/*` (除公开接口外)
- **站点管理**: `/adminapi/site/*`
- **其他业务接口**: 所有其他接口

### 路由路径对齐

#### PHP → NestJS 路径映射
```typescript
// PHP: /adminapi/sys/get/website
// NestJS: @Get('get/website') 在 @Controller('adminapi/sys')

// PHP: /adminapi/login
// NestJS: @Get('login') 在 @Controller('adminapi') + @Public()

// PHP: /adminapi/captcha/create
// NestJS: @Get('create') 在 @Controller('adminapi/captcha') + @Public()
```

### 最佳实践

#### 1. 控制器级别设置
```typescript
// 免登录控制器
@Controller('adminapi/login')
@Public() // 整个控制器免登录
export class LoginController {}

// 需要登录控制器
@Controller('adminapi/sys')
@UseGuards(JwtAuthGuard, RolesGuard) // 整个控制器需要登录
export class ConfigController {}
```

#### 2. 方法级别设置
```typescript
@Controller('adminapi/sys')
export class ConfigController {
  @Public() // 单个方法免登录
  @Get('web/website')
  async getWebWebsite() {}

  @Get('get/website') // 默认需要登录
  async getWebsite() {}
}
```

#### 3. 路径命名规范
- **PHP方法名**: `getWebsite()` → **NestJS路径**: `get/website`
- **PHP方法名**: `setWebsite()` → **NestJS路径**: `set/website`
- **PHP方法名**: `getSceneDomain()` → **NestJS路径**: `get/scene/domain`

### 验证方法

#### 1. 检查免登录接口
```bash
# 这些接口应该不需要token就能访问
curl http://localhost:3001/adminapi/login
curl http://localhost:3001/adminapi/captcha/create
curl http://localhost:3001/api/sys/website
```

#### 2. 检查需要登录接口
```bash
# 这些接口需要token才能访问
curl -H "Authorization: Bearer <token>" http://localhost:3001/adminapi/sys/get/website
curl -H "Authorization: Bearer <token>" http://localhost:3001/adminapi/site/lists
```

### 总结

NestJS的认证处理方式**更像Java Spring Boot**，使用装饰器模式：

1. **@Public()** = Java的 **@SaNotCheckLogin**
2. **默认需要登录** = Java的 **@SaCheckLogin**
3. **全局守卫** = Java的 **拦截器**

这种方式比PHP的中间件方式更加灵活和类型安全，符合现代框架的设计理念。
