时间:2024-12-06 22:51
人气:
作者:admin

创建一个 Asp.Net Core WebApi 项目
引用以下 Nuget 包:
Microsoft.AspNetCore.Authentication.JwtBearer
Microsoft.AspNetCore.Identity.EntityFrameworkCore
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
打开 appsettings.json 文件,配置数据库连接字符串和JWT的密钥、过期时间
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Default": "Server=(localdb)\\mssqllocaldb;Database=IdentityTestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"JWT": {
"SigningKey": "fasdfad&9045dafz222#fadpio@0232",
"ExpireSeconds": "86400"
}
}
创建JWT配置实体类 JWTOptions
public class JWTOptions
{
public string SigningKey { get; set; }
public int ExpireSeconds { get; set; }
}
打开 Program.cs 文件,在 builder.Build 之前,编写代码对 JWT 进行配置
// 注入 JWT 配置
services.Configure<JWTOptions>(builder.Configuration.GetSection("JWT"));
// 注入 JwtBearer 配置
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x => {
var jwtOpt = builder.Configuration.GetSection("JWT").Get<JWTOptions>();
byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOpt.SigningKey);
var secKey = new SymmetricSecurityKey(keyBytes);
x.TokenValidationParameters = new()
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = secKey
};
});
打开 Program.cs 文件,在 app.UseAuthorization 之前,添加身份验证中间件
// 使用 Authentication 中间件,放在 UseAuthorization 之前
app.UseAuthentication();
创建继承 IdentityRole 的 User 和 Role 实体类
using Microsoft.AspNetCore.Identity;
public class User: IdentityUser<long>
{
public DateTime CreationTime { get; set; }
public string? NickName { get; set; }
}
public class Role: IdentityRole<long>
{
}
创建继承 IdentityDbContext 的上下文类
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
public class IdDbContext: IdentityDbContext<User, Role, long>
{
public IdDbContext(DbContextOptions<IdDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
}
(可选)如果数据表还没创建,执行数据库迁移命令
创建登录请求的参数实体类 LoginRequest
public record LoginRequest(string UserName, string Password);
打开登录请求控制器,编写 Login API,在其中创建 JWT
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace ASPNETCore_JWT1.Controllers
{
[ApiController]
[Route("[controller]/[action]")]
public class Test1Controller : ControllerBase
{
private readonly UserManager<User> userManager;
//注入 UserManager
public Test1Controller(UserManager<User> userManager)
{
this.userManager = userManager;
}
// 生成 JWT
private static string BuildToken(IEnumerable<Claim> claims, JWTOptions options)
{
DateTime expires = DateTime.Now.AddSeconds(options.ExpireSeconds);
byte[] keyBytes = Encoding.UTF8.GetBytes(options.SigningKey);
var secKey = new SymmetricSecurityKey(keyBytes);
var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);
var tokenDescriptor = new JwtSecurityToken(
expires: expires, signingCredentials:
credentials,
claims: claims);
var result = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
return result;
}
// 在方法中注入 IOptions<JWTOptions>
// 只需要返回 JWT Token 即可,其它的身份验证中间件会处理
[HttpPost]
public async Task<IActionResult> Login(
LoginRequest req,
[FromServices] IOptions<JWTOptions> jwtOptions)
{
string userName = req.UserName;
string password = req.Password;
var user = await userManager.FindByNameAsync(userName);
if (user == null)
{
return NotFound($"用户名不存在{userName}");
}
if (await userManager.IsLockedOutAsync(user))
{
return BadRequest("LockedOut");
}
var success = await userManager.CheckPasswordAsync(user, password);
if (!success)
{
return BadRequest("Failed");
}
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
var roles = await userManager.GetRolesAsync(user);
foreach (string role in roles)
{
claims.Add(new Claim(ClaimTypes.Role, role));
}
var jwtToken = BuildToken(claims, jwtOptions.Value);
return Ok(jwtToken);
}
}
}
打开其它控制器,在类上添加 [Authorize] 这个特性
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
namespace ASPNETCore_JWT1.Controllers
{
// [Authorize] 特性标识此控制器的方法需要身份授权才能访问
// 授权中间件会处理其它的
[ApiController]
[Route("[controller]/[action]")]
[Authorize]
public class Test2Controller : Controller
{
[HttpGet]
public IActionResult Hello()
{
// ControllerBase中定义的ClaimsPrincipal类型的User属性代表当前登录用户的身份信息
// 可以通过ClaimsPrincipal的Claims属性获得当前登录用户的所有Claim信息
// this.User.Claims
string id = this.User.FindFirst(ClaimTypes.NameIdentifier)!.Value;
string userName = this.User.FindFirst(ClaimTypes.Name)!.Value;
IEnumerable<Claim> roleClaims = this.User.FindAll(ClaimTypes.Role);
string roleNames = string.Join(",", roleClaims.Select(c => c.Value));
return Ok($"id={id},userName={userName},roleNames ={roleNames}");
}
}
}
打开 Program.cs 文件,配置 Swagger,支持发送 Authorization 报文头
// 配置 Swagger 支持 Authorization
builder.Services.AddSwaggerGen(c => {
var scheme = new OpenApiSecurityScheme()
{
Description = "Authorization header. \r\nExample: 'Bearer 12345abcdef'",
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Authorization"
},
Scheme = "oauth2",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
};
c.AddSecurityDefinition("Authorization", scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List<string>();
c.AddSecurityRequirement(requirement);
});
using Microsoft.AspNetCore.Identity;
using Microsoft.OpenApi.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using System.Text;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
// 配置 Swagger 支持 Authorization
builder.Services.AddSwaggerGen(c => {
var scheme = new OpenApiSecurityScheme()
{
Description = "Authorization header. \r\nExample: 'Bearer 12345abcdef'",
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Authorization"
},
Scheme = "oauth2",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
};
c.AddSecurityDefinition("Authorization", scheme);
var requirement = new OpenApiSecurityRequirement();
requirement[scheme] = new List<string>();
c.AddSecurityRequirement(requirement);
});
var services = builder.Services;
// 注册数据库服务
services.AddDbContext<IdDbContext>(opt => {
string connStr = builder.Configuration.GetConnectionString("Default")!;
opt.UseSqlServer(connStr);
});
// 注册数据保护服务
services.AddDataProtection();
// 注册 IdentityCore 服务
services.AddIdentityCore<User>(options => {
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 6;
options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
});
// 注入UserManager、RoleManager等服务
var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services);
idBuilder.AddEntityFrameworkStores<IdDbContext>()
.AddDefaultTokenProviders()
.AddRoleManager<RoleManager<Role>>()
.AddUserManager<UserManager<User>>();
// 注入 JWT 配置
services.Configure<JWTOptions>(builder.Configuration.GetSection("JWT"));
// 注入 JwtBearer 配置
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x => {
var jwtOpt = builder.Configuration.GetSection("JWT").Get<JWTOptions>();
byte[] keyBytes = Encoding.UTF8.GetBytes(jwtOpt.SigningKey);
var secKey = new SymmetricSecurityKey(keyBytes);
x.TokenValidationParameters = new()
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = secKey
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
// 使用 Authentication 中间件,放在 UseAuthorization 之前
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
