.NET 8 集成 JWT Bearer Token

注意:这是一种非常简单且不是最低限度安全的设置 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本文先介绍到这里了。

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

相关推荐
我不会起名字3222 天前
Redis 从 0 到 1(十九):JWT 还是 Redis Session?登录态存储的 Go 实现
redis·go·jwt·session·登录态
Thanks_ks3 天前
Cookie 和 Session 到底是什么关系——登录态是怎么维持的
分布式·http·jwt·cookie·session·后端开发·登录态
枫子有风6 天前
卡码网盘项目深挖
java·redis·jwt·es·pgvector
FungLeo7 天前
成为全栈·Go 后端篇·跨语言认证兼容:Node 与 Go 如何互认 JWT 和密码
golang·go·jwt·身份认证·成为全栈·bcrypt
csdn_aspnet11 天前
.NETCore SqlSuagr 根据 mysql 数据表按顺序生成简单编号
mysql·.netcore·sqlsugar·1024程序员节·sequence·.net8·编号
积流成海16 天前
JWT 解析:三段结构、过期时间换算与常见误区
jwt·盘子工具站
FungLeo23 天前
成为全栈·Flutter App 篇·Refresh Token 旋转与并发 401:安全存储与会话代次
flutter·jwt·移动安全·身份认证·token刷新·成为全栈
豆角焖肉23 天前
SpringBoot+JWT 实现前后端分离登录鉴权
java·开发语言·spring boot·jwt·前后端分离·登录认证
CSharp精选营1 个月前
Blazor 里 JWT 过期,用户正下单就被踢
认证·jwt·webassembly·blazor·令牌刷新
LateFrames1 个月前
WPF 升级选型:用 .NET 8 还是 .NET 10
.net·wpf·.net8·.net10