IdentityServer4:密码模式
IdentityServer4:密码模式
IdentityServer4:密码授权模式
密码授权模式需要用户的参与,用户在客户端登录界面输入账号和密码,然后客户端将用户的账号和密码(有时也包括客户端的ClientID)发送往认证服务器换取 AccessToken,然后客户端在每次发往资源服务器的 Http请求中添加 AccessToken ,以此来访问资源服务器上受保护的资源。
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" };
});
代码解析:
- options.Authority: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,然后向资源服务器发送请求获取数据:
using IdentityModel.Client;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Dotnet.WebApi.Ids4.PwdClient
{
internal class DataService
{
private static readonly string ids4Url = "https://localhost:6001/";
/// <summary>
/// 获取AccessToken
/// </summary>
/// <returns></returns>
public static async Task<TokenResponse> GetAccessToken(string userName, string userPwd)
{
var client = new HttpClient();
//连接IDS4服务器
var disco = client.GetDiscoveryDocumentAsync(ids4Url).Result;
if (disco.IsError)
{
Console.WriteLine(disco.Error);
}
//客户端信息
var tokenclient = new TokenClient(client, new TokenClientOptions
{
ClientId = "AppProductAddClient",
ClientSecret = "App00000002",
Address = disco.TokenEndpoint,
});
//根据用户名和密码换取Token
var token = await tokenclient.RequestPasswordTokenAsync(userName, userPwd, "Product.Add");
return token;
}
private static readonly string apiUrl = "https://localhost:6012/api/product/add";
/// <summary>
/// 添加API数据。
/// </summary>
/// <param name="accessToken"></param>
/// <returns></returns>
public static string AddAPIData(string accessToken)
{
string result = "";
// 实例化HttpClient
HttpClient httpClient = new HttpClient();
//将AccessToken附加到HTTP请求的头部。
httpClient.SetBearerToken(accessToken);
//实例化Product实体模型类
Product product = new Product()
{
Id = 1,
Name = "EX-升降椅"
};
//将Product对象序列化为JSON字符串。
var s = JsonConvert.SerializeObject(product);
//实例化HttpContent对象,封装请求内容。
//设置编码为utf-8,媒体类型是application/json。
HttpContent httpContent = new StringContent(s, Encoding.UTF8, "application/json");
//调用PostAsync()方法执行Post请求。
var data = httpClient.PostAsync(apiUrl, httpContent);
//如果请求成功
if (data.Result.StatusCode == HttpStatusCode.OK)
{
result = data.Result.Content.ReadAsStringAsync().Result;
}
return result;
}
}
}
运行成功后,需要用户在控制台终端中输入用户名和密码来换取 AccessToken,然后才能获取到受保护的Api数据。
转载至:https://www.cnblogs.com/easy5weikai/p/17198709.html
posted on 2023-11-21 17:11 一只小青蛙-呱-呱-dyj 阅读(35) 评论(0) 编辑 收藏 举报