IdentityServer4:密碼授權模式
Api 資源項目
創建項目
打開 VS,創建一個“AspNet Core WebApi” 項目, 名爲:Dotnet.WebApi.Ids4.ProductApi
依賴包
添加依賴包
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.3" />
添加認證方案
修改 Program.cs 爲如下代碼:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using System;
namespace Dotnet.WebApi.Ids4.ProductApi
{
public class Program
{
public static void Main(string[] args)
{
Console.Title = "ProductAPI服務器";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
//IdentityServer4地址
options.Authority = "https://localhost:6001";
//認證的ApiResource名稱
options.Audience = "ProductAPIResource";
//使用JWT認證類型
options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.Urls.Add("https://*:6012");
app.UseHttpsRedirection();
//身份驗證
app.UseAuthentication();
//授權
app.UseAuthorization();
app.MapControllers();
app.Run();
}
}
}
其中:
(1)添加 JWT 認證:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
//IdentityServer4地址
options.Authority = "https://localhost:6001";
//認證的ApiResource名稱
options.Audience = "CustomerAPIResource";
//使用JWT認證類型
options.TokenValidationParameters.ValidTypes = new[] { "at+jwt" };
});
https://localhost:6001 是認證服務器地址。
添加 Api
新增文件:Controllers/ProductController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Dotnet.WebApi.Ids4.ProductApi.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
/// <summary>
/// 添加產品
/// </summary>
/// <param name="product"></param>
/// <returns></returns>
[HttpPost("Add")]
public ActionResult<string> Add(Product product)
{
var productId = product.Id;
var productName = product.Name;
//保存操作
//........
return $"productId:{productId}, productName:{productName}";
}
}
}
其中:
(1)在控制器上添加特性:[Authorize],這樣只有登錄用戶才能訪問,這樣就起到保護了Api資源的目的。
Product.cs
namespace Dotnet.WebApi.Ids4.PwdClient
{
internal class Product
{
//唯一ID
public int Id { get; set; }
//產品名稱
public string? Name { get; set; }
}
}
認證服務器
創建項目
打開 VS,創建一個“AspNet Core 空” 項目,名爲:Dotnet.WebApi.Ids4.AuthService
依賴包
添加依賴包
<PackageReference Include="IdentityServer4" Version="4.1.2" />
配置 IdentityServer4
創建文件:IdentityConfig.cs,添加如下代碼:
using IdentityServer4.Models;
using IdentityServer4.Test;
namespace Dotnet.WebApi.Ids4.AuthService
{
public static class IdentityConfig
{
/// <summary>
/// 配置API作用域。
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiScope> GetApiScopes()
{
return new List<ApiScope>
{
//產品相關API作用域
new ApiScope("Product.Read","讀取產品信息。"),
new ApiScope("Product.Add","添加產品信息。"),
//共享API作用域
new ApiScope("News","新聞信息。")
};
}
/// <summary>
/// 配置ApiResource。
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApiResources()
{
//將多個具體的APIScope歸爲一個ApiResource。
return new List<ApiResource>()
{
new ApiResource("ProductAPIResource","產品資源")
{
Scopes={ "Product.Read", "Product.Add" ,"News" }
}
};
}
/// <summary>
/// 配置客戶端應用。
/// </summary>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
new Client
{
//客戶端ID。
ClientId = "AppProductAddClient",
//密碼模式
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
//認證密鑰。
ClientSecrets =
{
new Secret("App00000002".Sha256())
},
//客戶端有權訪問的範圍。
AllowedScopes={ "Product.Add" }
}
};
}
/// <summary>
/// 配置用戶。
/// </summary>
/// <returns></returns>
public static List<TestUser> GetUsers()
{
return new List<TestUser>()
{
new TestUser
{
SubjectId="1",
Username="zhagnsan",
Password="123456"
}
};
}
}
}
密碼授權模式需要用戶輸入用戶名和密碼來換取 AccessToken, 故相較於客戶端模式,需做如下調整:
(1)Client的授權模式修改爲密碼模式;
IdentityConfig.cs
new Client
{
......
//客戶端ID。
ClientId = "AppProductAddClient",
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
}
(2)添加用戶
代碼清單;IdentityConfig.cs
/// <summary>
/// 配置用戶。
/// </summary>
/// <returns></returns>
public static List<TestUser> GetUsers()
{
return new List<TestUser>()
{
new TestUser
{
SubjectId="1",
Username="zhagnsan",
Password="123456"
}
};
}
然後在 Program.cs 中註冊 IdentityServer 時, 添加用戶
//註冊IdentityServer4組件
builder.Services.AddIdentityServer()
......
.AddTestUsers(IdentityConfig.GetUsers())
集成 IdentityServer4
修改 Program.cs 爲如下代碼:
namespace Dotnet.WebApi.Ids4.AuthService
{
public class Program
{
public static void Main(string[] args)
{
Console.Title = "認證和授權服務器";
var builder = WebApplication.CreateBuilder(args);
//註冊IdentityServer4組件
builder.Services.AddIdentityServer()
.AddInMemoryApiScopes(IdentityConfig.GetApiScopes())
.AddInMemoryApiResources(IdentityConfig.GetApiResources())
.AddInMemoryClients(IdentityConfig.GetClients())
.AddTestUsers(IdentityConfig.GetUsers())
.AddDeveloperSigningCredential(); // 添加臨時內存中的證書
var app = builder.Build();
//修改端口號
app.Urls.Add("https://*:6001");
//添加IDS4中間件。
//在瀏覽器中輸入如下地址訪問 IdentityServer4 的發現文檔:https://localhost:6001/.well-known/openid-configuration
app.UseIdentityServer();
app.Run();
}
}
}
其中,app.Urls.Add("https://*:6001");
設置認證服務器的監聽端口爲:6001
密碼模式客戶端
創建項目
新控制檯項目,名爲:Dotnet.WebApi.Ids4.PwdClient
依賴包
添加依賴包
<PackageReference Include="IdentityServer4" Version="4.1.2" />
Program.cs
將 Program.cs 的代碼修改爲;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Dotnet.WebApi.Ids4.PwdClient
{
internal class Program
{
static void Main(string[] args)
{
Console.Title = "密碼授權模式客戶端";
Console.Write("請輸入用戶名:");
var userName = Console.ReadLine();
Console.Write("請輸入密碼:");
var userPwd = Console.ReadLine();
//獲取AccessToken
var token = DataService.GetAccessToken(userName!, userPwd!).Result.AccessToken;
Console.WriteLine(token);
//操作API資源
var result = DataService.AddAPIData(token);
Console.WriteLine(result);
Console.ReadKey();
}
}
}
DataService.cs
DataService 類 演示瞭如何從認證服務器獲取 AccessToken,然後向資源服務器發送請求獲取數據:
namespace Dotnet.WebApi.Ids4.PwdClient
{
internal class Program
{
static void Main(string[] args)
{
Console.Title = "密碼授權模式客戶端";
Console.Write("請輸入用戶名:");
var userName = Console.ReadLine();
Console.Write("請輸入密碼:");
var userPwd = Console.ReadLine();
//獲取AccessToken
var token = DataService.GetAccessToken(userName!, userPwd!).Result.AccessToken;
Console.WriteLine(token);
//操作API資源
var result = DataService.AddAPIData(token);
Console.WriteLine(result);
Console.ReadKey();
}
}
}
運行成功後,需要用戶在控制檯終端中輸入用戶名和密碼來換取 AccessToken,然後才能獲取到受保護的Api數據。