.NET 8 集成 JWT Bearer Token

发布于:2025-09-02 ⋅ 阅读:(24) ⋅ 点赞:(0)

注意:这是一种非常简单且不是最低限度安全的设置 JWT 的方法。

步骤 1——安装软件包

首先,您需要安装一些 NuGet 包。

dotnet add package Microsoft.AspCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt

步骤 2——创建类

你需要创建一些类来处理登录请求、注册请求和授权响应。你还需要某种类型的用户。

using System.ComponentModel.DataAnnotations;

namespace Auth;

public class LoginRequest
{
    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }
}

using System.ComponentModel.DataAnnotations;

namespace Auth;

public class RegistrationRequest
{
    [Required]
    public string UserID { get; set; }

    [Required]
    public string Username { get; set; }

    [Required]
    public string Firstname { get; set; }

    [Required]
    public string Lastname { get; set; }

    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    public string Password { get; set; }
}

namespace Auth;

public class AuthResponse
{
    public string UserId { get; set; }
    public string Username { get; set; }
    public string Token { get; set; }
    public string? ProfileImage { get; set; }
}

步骤 3——创建控制器

当我们创建了类之后,我们需要实现注册用户和登录的逻辑。我将跳过创建用户的逻辑,只在我的示例中使用我的服务,您需要自己做这件事。

[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegistrationRequest request)
{
    var salt = GenerateSalt();
    var saltedPassword = request.Password + salt;

    var user = new User
    {
        Firstname = request.Firstname,
        Lastname = request.Lastname,
        Email = request.Email,
        Password = _passwordHasher.HashPassword(null, saltedPassword),    // Null is because the user is not created yet, normally this is where the user object is.
        Salt = salt,
        Role = Enums.Role.USER
    };

    await _userService.CreateUser(user);
    var token = _tokenService.CreateToken(user);

    return Ok(new AuthResponse { Token = token });
}

[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
    User? user = await _userService.FindByEmailAsync(request.Email);        

    if (user == null)
    {
        return Unauthorized("Invalid credentials 1");
    }

    var saltedPassword = request.Password + user.Salt;
    
    var result = _passwordHasher.VerifyHashedPassword(user, user.Password,saltedPassword);

    if (result != PasswordVerificationResult.Success)
    {
        return Unauthorized("Invalid credentials 2");
    }

    // Generate token
    var token = _tokenService.CreateToken(user);

    // Return the token
    return Ok(new AuthResponse { Token = token });
}

步骤4 —创建令牌服务

现在我们需要创建一个生成 JWT 令牌的方法。在我们的令牌中,我们可以添加任意数量的索赔正如我们想要的那样。这里需要注意的是,我们的 SecurityTokenDescriptor 必须具有与“Program.cs”中的授权设置相同的令牌验证参数。我们稍后会再讨论这一点。我在这里使用的名为“_configuration”的变量,正是通过“IConfiguration”依赖注入到我的控制器中的。

public string CreateToken(User user)
{
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(new Claim[]
        {
            new Claim(ClaimTypes.NameIdentifier, user.UserID),
            new Claim(ClaimTypes.Role, user.Role.ToString()),
            // Add more claims as needed
        }),
        Expires = DateTime.UtcNow.AddHours(1),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
        Issuer = _configuration["Jwt:Issuer"], // Add this line
        Audience = _configuration["Jwt:Audience"] 
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);
    return tokenHandler.WriteToken(token);
}

步骤 5 — 设置 Swagger 配置

现在我们需要配置 Swagger,以便稍后测试我们的端点。这里需要注意的是,当我们在 Swagger 的授权输入框中输入令牌字符串时,需要依次输入:Bearer,后跟一个空格,然后是令牌字符串。

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new() { Title = "Pappa´s API", Version = "v1" });

    // Define the OAuth2.0 scheme that's in use (i.e., Implicit Flow)
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    c.AddSecurityRequirement(new OpenApiSecurityRequirement()
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference
                {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                },
                Scheme = "oauth2",
                Name = "Bearer",
                In = ParameterLocation.Header,
            },
            new List<string>()
        }
    });
});

步骤 6——设置授权

这里重要的是,我们的令牌验证参数与我们在令牌服务中的“CreateToken”方法中添加的参数相同。

builder.Services.AddAuthentication(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"])),
            ClockSkew = TimeSpan.Zero
        };
    });

步骤 7——设置中间件

我们放置中间件的顺序非常重要,所以不要弄错顺序。我们也指定 Swagger 仅在开发环境中有效。

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.MapControllers();

步骤 8 — 设置应用程序设置

现在我们需要将 JWT 值添加到我们的“apptsettings.json”文件中,包括密钥、颁发者和受众。出于演示和开发目的,我仅使用这些简单的值。但请注意,密钥尤其不应以纯文本形式存储,为了安全起见,最好将所有值存储在安全的地方,例如 Azure Secrets 或 GitHub Secrets。

"Jwt": {
    "Key": "your_secret_key_here_your_secret_key_here",
    "Issuer": "your_issuer",
    "Audience": "your_audience"
  }

步骤 9 — 在控制器中设置授权

现在是时候将我们的令牌集成到我们的某个 API 中了。为此,我们让 .NET 处理编码,就像我们在“Program.cs”文件中设置的那样。我们还添加了“[Authroize]”和“Roles”,以实现基于角色的身份验证。如果您想添加更多角色,只需在同一字符串中用逗号分隔它们即可。

[HttpGet("getuser")]
    [Authorize(Roles = "USER")]
    public async Task<ActionResult<User>> GetUser()
    {
        // Retrieve userId from the claims
        var userIdClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;
        
        Console.WriteLine("Claims received:");
        foreach (var claim in User.Claims)
        {
            Console.WriteLine($"{claim.Type}: {claim.Value}");
        }

        if(userIdClaim == null)
        {
            return Unauthorized("No user ID claim present in token.");
        }
        
        try
        {
            User? user = await _userService.GetUser(userIdClaim);
            return Ok(user);
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(ex.Message);
        }
    }
    
关于.NET8集成JWT本文先介绍到这里了。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。


网站公告

今日签到

点亮在社区的每一天
去签到