bun-server-security

📁 dangaogit/bun-server-skills 📅 9 days ago
1
总安装量
1
周安装量
#45148
全站排名
安装命令
npx skills add https://github.com/dangaogit/bun-server-skills --skill bun-server-security

Agent 安装分布

trae 1
qoder 1
trae-cn 1
cursor 1
claude-code 1

Skill 文档

Bun Server Security

Setup SecurityModule

import { Module, SecurityModule } from "@dangao/bun-server";

SecurityModule.forRoot({
  jwt: {
    secret: process.env.JWT_SECRET!,
    expiresIn: "1h",
    algorithm: "HS256",
  },
  oauth2: {
    github: {
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      authorizationUrl: "https://github.com/login/oauth/authorize",
      tokenUrl: "https://github.com/login/oauth/access_token",
      userInfoUrl: "https://api.github.com/user",
      redirectUri: "http://localhost:3100/auth/github/callback",
      scope: ["user:email"],
    },
  },
});

@Module({
  imports: [SecurityModule],
})
class AppModule {}

Guards

Using Built-in Guards

import {
  Controller,
  GET,
  UseGuards,
  Roles,
  AuthGuard,
  RolesGuard,
} from "@dangao/bun-server";

@Controller("/api")
@UseGuards(AuthGuard) // Require authentication
class ApiController {
  @GET("/profile")
  getProfile() {
    return { message: "Authenticated user only" };
  }

  @GET("/admin")
  @UseGuards(RolesGuard)
  @Roles("admin")
  adminOnly() {
    return { message: "Admin only" };
  }

  @GET("/manager")
  @UseGuards(RolesGuard)
  @Roles("admin", "manager") // Either role
  managerArea() {
    return { message: "Admin or manager" };
  }
}

Custom Guard

import { CanActivate, ExecutionContext, Injectable } from "@dangao/bun-server";

@Injectable()
class ApiKeyGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean | Promise<boolean> {
    const http = context.switchToHttp();
    const request = http.getRequest();

    const apiKey = request.headers.get("x-api-key");
    return apiKey === process.env.API_KEY;
  }
}

// Usage
@Controller("/api")
@UseGuards(ApiKeyGuard)
class ExternalApiController {}

JWT Authentication

Generate Token

import { Injectable, JWTUtil, Inject, JWT_UTIL_TOKEN } from "@dangao/bun-server";

@Injectable()
class AuthService {
  constructor(@Inject(JWT_UTIL_TOKEN) private readonly jwt: JWTUtil) {}

  async login(email: string, password: string) {
    const user = await this.validateUser(email, password);
    if (!user) {
      throw new UnauthorizedException("Invalid credentials");
    }

    const token = this.jwt.sign({
      sub: user.id,
      email: user.email,
      roles: user.roles,
    });

    return { accessToken: token };
  }
}

Verify Token

@Injectable()
class AuthService {
  constructor(@Inject(JWT_UTIL_TOKEN) private readonly jwt: JWTUtil) {}

  verifyToken(token: string) {
    try {
      const payload = this.jwt.verify(token);
      return payload;
    } catch (error) {
      throw new UnauthorizedException("Invalid token");
    }
  }
}

OAuth2 Authentication

import {
  Controller,
  GET,
  Query,
  Inject,
  OAuth2Service,
  OAUTH2_SERVICE_TOKEN,
} from "@dangao/bun-server";

@Controller("/auth")
class AuthController {
  constructor(
    @Inject(OAUTH2_SERVICE_TOKEN) private readonly oauth2: OAuth2Service
  ) {}

  @GET("/github")
  githubLogin() {
    const url = this.oauth2.getAuthorizationUrl("github");
    return ResponseBuilder.redirect(url);
  }

  @GET("/github/callback")
  async githubCallback(@Query("code") code: string) {
    const tokens = await this.oauth2.exchangeCode("github", code);
    const userInfo = await this.oauth2.getUserInfo("github", tokens.access_token);

    // Create or update user
    const user = await this.userService.findOrCreate(userInfo);

    // Generate JWT
    const jwt = this.authService.generateToken(user);

    return { accessToken: jwt };
  }
}

Security Context

Access authenticated user info:

import {
  SecurityContextHolder,
  Controller,
  GET,
  UseGuards,
  AuthGuard,
} from "@dangao/bun-server";

@Controller("/api")
@UseGuards(AuthGuard)
class UserController {
  @GET("/me")
  getCurrentUser() {
    const context = SecurityContextHolder.getContext();
    const authentication = context.getAuthentication();

    return {
      userId: authentication.getPrincipal().id,
      email: authentication.getPrincipal().email,
      roles: authentication.getAuthorities(),
    };
  }
}

Role-based Access Control

@Controller("/api/admin")
@UseGuards(AuthGuard, RolesGuard)
@Roles("admin")
class AdminController {
  @GET("/users")
  listUsers() {
    return this.userService.findAll();
  }

  @DELETE("/users/:id")
  @Roles("super-admin") // Override class-level roles
  deleteUser(@Param("id") id: string) {
    return this.userService.delete(id);
  }
}

Auth Decorator (Legacy)

import { Auth, Controller, GET } from "@dangao/bun-server";

@Controller("/api")
class ApiController {
  @GET("/protected")
  @Auth() // Requires authentication
  protected() {
    return { message: "Protected" };
  }

  @GET("/admin")
  @Auth({ roles: ["admin"] })
  adminOnly() {
    return { message: "Admin only" };
  }
}

Security Filter

Apply security globally:

import { Application, createSecurityFilter } from "@dangao/bun-server";

const app = new Application({ port: 3100 });

// Add security filter
app.use(createSecurityFilter({
  excludePaths: ["/public", "/health"],
}));

Related Resources