ASP.NET Core中提供了多种身份证认证模式,几种常见的身份认证模式有以下几种。本文将详细介绍一下JWT身份认证在ASP.NET Core中如何使用。
认证模式 |
介绍 |
Cookie |
最常见的身份认证方式之一。用户登录成功后,服务器会生成一个加密的 Cookie 并发送给客户端,客户端在后续请求中携带该 Cookie 来验证用户身份。 |
JWT |
JSON Web Token)是一种基于 JSON 的开放标准(RFC 7519),用于在网络上安全地传输声明。JWT 认证通过在客户端和服务器之间传递加密的 Token 来验证用户身份。 |
OAuth |
一种开放标准,用于授权第三方应用程序访问用户数据。ASP.NET Core 提供了 OAuth 认证机制,允许应用程序通过 OAuth 协议与第三方身份提供者进行集成。 |
OpenID Connect |
建立在 OAuth 2.0 协议之上的身份认证协议,用于验证用户身份。ASP.NET Core 提供了对 OpenID Connect 的支持,可以与支持 OpenID Connect 的身份提供者集成。 |
Windows |
ASP.NET Core 支持 Windows 身份认证,允许用户使用他们的 Windows 凭据登录到应用程序。 |
项目(新建的WebApi)结构如图所示:
实际代码示例如下:
Program.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new()
{
//NameClaimType = "",
//RoleClaimType = "",
//是否验证Issuer
ValidateIssuer = true,
//是否验证Audience
ValidateAudience = true,
//是否验证失效时间
ValidateLifetime = true,
//是否验证SecurityKey
ValidateIssuerSigningKey = true,
//Audience
ValidAudience = "MDCClient",
//Issuer,这两项和签发jwt的设置一致
ValidIssuer = "MDCServer",
//SecurityKey
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("KKqUZx15DF2y01rPNaPOYr4doES59Mbu"))
};
});
builder.Services.AddAuthorization(options =>
{
//Claim中携带Admin即可通过认证
//options.AddPolicy("Admin", policy =>policy.RequireClaim("Admin"));
//Role角色为Admin通过认证
options.AddPolicy("Admin", policy => policy.RequireRole("Admin"));
});
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
//启用跨域
app.UseCors(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
//启用授权
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
AuthController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace JWT.Controllers
{
public class AuthController : Controller
{
[HttpPost]
public string GetToken(string userName, string password)
{
// 验证用户名和密码逻辑
if (userName == "admin" && password == "password")
{
return GenerateToken(userName);
}
return "Login failed";
}
[Authorize]
[HttpGet]
public string TestAuth()
{
return "Access JWT Auth Success!";
}
[Authorize(Policy = "Admin")]
[HttpGet]
public string TestAuthAdmin()
{
return "Access JWT Admin Auth Success!";
}
///
/// 生成Token
///
///
///
private string GenerateToken(string userName)
{
List claims = new()
{
//new Claim(ClaimTypes.Name,userName),
//放开这段代码 TestAuthAdmin请求会正常返回数据
new Claim(ClaimTypes.Role,"Admin")
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("KKqUZx15DF2y01rPNaPOYr4doES59Mbu"));
var expires = DateTime.Now.AddDays(30);
var token = new JwtSecurityToken(
issuer: "MDCServer",
audience: "MDCClient",
claims: claims,
notBefore: DateTime.Now,
expires: expires,
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
}
Program.cs
// See https://aka.ms/new-console-template for more information
using System.Net.Http.Headers;
Console.OutputEncoding = System.Text.Encoding.Unicode;
Console.WriteLine("Hello, World!");
using (var client =new HttpClient())
{
var token = "";
var parameters = new Dictionary
{
{ "userName", "admin" },
{ "password", "password" }
};
var content = new FormUrlEncodedContent(parameters);
Console.WriteLine("请求授权接口获取Token......");
HttpResponseMessage response = await client.PostAsync("http://localhost:5000/Auth/GetToken", content);
if (response.IsSuccessStatusCode)
{
token =await response.Content.ReadAsStringAsync();
Console.WriteLine("获取Token成功:");
Console.WriteLine(token);
}
else
{
Console.WriteLine("获取Token失败!");
return;
}
Console.WriteLine("未设置Token时请求Authorize接口...");
response = await client.GetAsync("http://localhost:5000/Auth/TestAuth");
Console.WriteLine($"请求Authorize接口状态码:{response.StatusCode}");
Console.WriteLine("设置Token...");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
response = await client.GetAsync("http://localhost:5000/Auth/TestAuth");
Console.WriteLine($"请求Auth 接口状态码:{response.StatusCode}");
Console.WriteLine($"请求Auth 接口结果:{await response.Content.ReadAsStringAsync()}");
response = await client.GetAsync("http://localhost:5000/Auth/TestAuthAdmin");
Console.WriteLine($"请求Admin Auth接口状态码:{response.StatusCode}");
Console.WriteLine($"请求Admin Auth接口结果:{await response.Content.ReadAsStringAsync()}");
}
Console.ReadKey();
属性 |
参数 |
作用 |
ValidateIssuer |
true |
是否验证Issuer |
ValidateAudience |
true |
是否验证Audience |
ValidateLifetime |
true |
是否验证失效时间 |
ValidateIssuerSigningKey |
true |
是否验证SecurityKey |
ValidAudience |
MDCClient |
Audience |
ValidIssuer |
MDCServer |
Issuer,这两项和签发jwt的设置一致 |
IssuerSigningKey |
new SymmetricSecurityKey (System.Text.Encoding.UTF8.GetBytes ("KKqUZx15DF2y01rPNaPOYr4doES59Mbu")) |
SecurityKey |
RequireRole表示Cookie的Claim的ClaimTypes.Role必须包含"Admin"才视为授权。
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new()
{
//NameClaimType = "",
//RoleClaimType = "",
//是否验证Issuer
ValidateIssuer = true,
//是否验证Audience
ValidateAudience = true,
//是否验证失效时间
ValidateLifetime = true,
//是否验证SecurityKey
ValidateIssuerSigningKey = true,
//Audience
ValidAudience = "MDCClient",
//Issuer,这两项和签发jwt的设置一致
ValidIssuer = "MDCServer",
//SecurityKey
IssuerSigningKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("KKqUZx15DF2y01rPNaPOYr4doES59Mbu"))
};
});
builder.Services.AddAuthorization(options =>
{
//Claim中携带Admin即可通过认证
//options.AddPolicy("Admin", policy =>policy.RequireClaim("Admin"));
//Role角色为Admin通过认证
options.AddPolicy("Admin", policy => policy.RequireRole("Admin"));
});
//启用跨域
app.UseCors(builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
app.UseAuthentication();
app.UseAuthorization();
GetToken的方法上用来获取服务器生成的Token并返回给客户端,这边的参数需要与AddJwtBearer里的option参数一致。
[HttpPost]
public string GetToken(string userName, string password)
{
// 验证用户名和密码逻辑
if (userName == "admin" && password == "password")
{
return GenerateToken(userName);
}
return "Login failed";
}
///
/// 生成Token
///
///
///
private string GenerateToken(string userName)
{
List claims = new()
{
//new Claim(ClaimTypes.Name,userName),
//放开这段代码 TestAuthAdmin请求会正常返回数据
new Claim(ClaimTypes.Role,"Admin")
};
var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes("KKqUZx15DF2y01rPNaPOYr4doES59Mbu"));
var expires = DateTime.Now.AddDays(30);
var token = new JwtSecurityToken(
issuer: "MDCServer",
audience: "MDCClient",
claims: claims,
notBefore: DateTime.Now,
expires: expires,
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256));
return new JwtSecurityTokenHandler().WriteToken(token);
}
[Authorize]
[HttpGet]
public string TestAuth()
{
return "Access JWT Auth Success!";
}
[Authorize(Policy = "Admin")]
[HttpGet]
public string TestAuthAdmin()
{
return "Access JWT Admin Auth Success!";
}
客户端分别演示了未携带Token,以及在请求头携带Token访问的情况。
// See https://aka.ms/new-console-template for more information
using System.Net.Http.Headers;
Console.OutputEncoding = System.Text.Encoding.Unicode;
Console.WriteLine("Hello, World!");
using (var client =new HttpClient())
{
var token = "";
var parameters = new Dictionary
{
{ "userName", "admin" },
{ "password", "password" }
};
var content = new FormUrlEncodedContent(parameters);
Console.WriteLine("请求授权接口获取Token......");
HttpResponseMessage response = await client.PostAsync("http://localhost:5000/Auth/GetToken", content);
if (response.IsSuccessStatusCode)
{
token =await response.Content.ReadAsStringAsync();
Console.WriteLine("获取Token成功:");
Console.WriteLine(token);
}
else
{
Console.WriteLine("获取Token失败!");
return;
}
Console.WriteLine("未设置Token时请求Authorize接口...");
response = await client.GetAsync("http://localhost:5000/Auth/TestAuth");
Console.WriteLine($"请求Authorize接口状态码:{response.StatusCode}");
Console.WriteLine("设置Token...");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
response = await client.GetAsync("http://localhost:5000/Auth/TestAuth");
Console.WriteLine($"请求Auth 接口状态码:{response.StatusCode}");
Console.WriteLine($"请求Auth 接口结果:{await response.Content.ReadAsStringAsync()}");
response = await client.GetAsync("http://localhost:5000/Auth/TestAuthAdmin");
Console.WriteLine($"请求Admin Auth接口状态码:{response.StatusCode}");
Console.WriteLine($"请求Admin Auth接口结果:{await response.Content.ReadAsStringAsync()}");
}
Console.ReadKey();