C# WebAPI Token 生成与账号密码登录实现

此为一个简单的且完整的 C# WebAPI 实现,用于基于账号密码的 Token 生成和验证系统。这个实现使用 JWT (JSON Web Token) 作为认证机制。

1. 创建项目

首先创建一个 ASP.NET Core WebAPI 项目。

2. 安装必要 NuGet 包

Microsoft.AspNetCore.Authentication.JwtBearer
System.IdentityModel.Tokens.Jwt
Microsoft.EntityFrameworkCore (如果使用数据库)
Microsoft.EntityFrameworkCore.SqlServer (如果使用SQL Server)

3. 完整实现代码

3.1 配置类 (appsettings.json)

{
  "Jwt": {
    "Key": "YourSuperSecretKeyHereAtLeast32CharactersLong",
    "Issuer": "YourAppIssuer",
    "Audience": "YourAppAudience",
    "ExpireMinutes": 60
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

3.2 用户模型 (Models/User.cs)

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public string Password { get; set; } // 实际应用中应该存储哈希值
    public string Role { get; set; } // 例如 "Admin", "User" 等
}

3.3 Token 响应模型 (Models/TokenResponse.cs)

public class TokenResponse
{
    public string Token { get; set; }
    public DateTime Expiration { get; set; }
    public string Username { get; set; }
    public string Role { get; set; }
}

3.4 登录请求模型 (Models/LoginRequest.cs)

public class LoginRequest
{
    public string Username { get; set; }
    public string Password { get; set; }
}

3.5 JWT 服务 (Services/JwtService.cs)

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;

public class JwtService
{
    private readonly IConfiguration _configuration;

    public JwtService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string GenerateToken(User user)
    {
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.Username),
            new Claim(ClaimTypes.Role, user.Role)
        };

        var token = new JwtSecurityToken(
            _configuration["Jwt:Issuer"],
            _configuration["Jwt:Audience"],
            claims,
            expires: DateTime.Now.AddMinutes(Convert.ToDouble(_configuration["Jwt:ExpireMinutes"])),
            signingCredentials: credentials);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

3.6 用户服务 (Services/UserService.cs)

public class UserService
{
    // 实际应用中应该从数据库获取用户
    private readonly List<User> _users = new List<User>
    {
        new User { Id = 1, Username = "admin", Password = "admin123", Role = "Admin" },
        new User { Id = 2, Username = "user", Password = "user123", Role = "User" }
    };

    public User Authenticate(string username, string password)
    {
        // 实际应用中应该验证密码哈希
        var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);

        // 如果用户不存在或密码错误返回null
        if (user == null)
            return null;

        // 认证成功返回用户详情 (不包含密码)
        return user;
    }
}

3.7 认证控制器 (Controllers/AuthController.cs)

using Microsoft.AspNetCore.Mvc;

[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly UserService _userService;
    private readonly JwtService _jwtService;

    public AuthController(UserService userService, JwtService jwtService)
    {
        _userService = userService;
        _jwtService = jwtService;
    }

    [HttpPost("login")]
    public IActionResult Login([FromBody] LoginRequest request)
    {
        var user = _userService.Authenticate(request.Username, request.Password);

        if (user == null)
            return Unauthorized(new { message = "用户名或密码错误" });

        var token = _jwtService.GenerateToken(user);

        return Ok(new TokenResponse
        {
            Token = token,
            Expiration = DateTime.Now.AddMinutes(Convert.ToDouble(_configuration["Jwt:ExpireMinutes"])),
            Username = user.Username,
            Role = user.Role
        });
    }
}

3.8 受保护资源控制器 (Controllers/ProtectedController.cs)

using Microsoft.AspNetCore.Authorization;

[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ProtectedController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        // 可以从HttpContext.User获取用户信息
        var username = User.Identity.Name;
        var role = User.FindFirst(ClaimTypes.Role)?.Value;

        return Ok(new { 
            Message = $"你好 {username}, 你的角色是 {role}",
            Data = "这是受保护的数据" 
        });
    }

    [Authorize(Roles = "Admin")]
    [HttpGet("admin")]
    public IActionResult AdminOnly()
    {
        return Ok(new { Message = "只有管理员能看到这条消息" });
    }
}

3.9 Program.cs 配置

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// 添加服务到容器
builder.Services.AddControllers();

// 配置JWT认证
builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        ValidAudience = builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
    };
});

// 注册自定义服务
builder.Services.AddScoped<UserService>();
builder.Services.AddScoped<JwtService>();

var app = builder.Build();

// 配置HTTP请求管道
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();

// 添加认证和授权中间件
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

4. 使用说明

4.1 获取Token

发送POST请求到 /api/auth/login,请求体为:

{
    "username": "admin",
    "password": "admin123"
}

成功响应示例:

{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expiration": "2023-05-01T12:00:00",
    "username": "admin",
    "role": "Admin"
}

4.2 访问受保护资源

在请求头中添加:

Authorization: Bearer <your_token>

然后访问 /api/protected

4.3 访问管理员资源

在请求头中添加:

Authorization: Bearer <your_token>

然后访问 /api/protected/admin (需要管理员角色)

5. 安全建议

  1. 密码存储:实际应用中不要明文存储密码,应该使用密码哈希加盐
  2. HTTPS:确保所有认证请求都通过HTTPS
  3. Token过期:设置合理的Token过期时间
  4. 密钥保护:保护JWT密钥,不要硬编码在代码中
  5. 刷新Token:考虑实现刷新Token机制

6. 扩展功能

  1. 添加用户注册功能
  2. 实现密码重置
  3. 添加多因素认证
  4. 实现Token刷新机制
  5. 添加日志记录和监控