.. | ||
ClaimKeyValue.cs | ||
ClaimTicketModelBinding.cs | ||
ClaimTicketModelBindingProvider.cs | ||
ClaimTicketOptions.cs | ||
ITicketBuilder.cs | ||
Readme.md | ||
ServiceCollectionExtend.cs | ||
TicketBuilder.cs | ||
UserTicket.cs |
客户凭据 Falcon.SugarApi.ClaimTicket.ClaimTicket
1、添加ClaimTicket支持。
是否使用ClaimTicket由插件自行决定。
如果插件需要使用ClaimTicket,按如下方式在插件服务配置中添加。
public class ServicePlugin:IServicePlugin
{
IServiceCollection IServicePlugin.AddServices(IServiceCollection services,IConfiguration configuration) {
//注入使用ClaimTicket的控制器
services.AddPluginsController(this.GetType().Assembly);
//添加ClaimTicket服务支持
services.AddClaimTicket();
return services;
}
}
2、控制器注入
要完成用户的登录,认证和绑定工作需要注入ITicketBuilder接口,这个接口在上面的services.AddClaimTicket()中已经完成注入。
下面是在HomeController控制器中注入ITicketBuilder的示例。
public ITicketBuilder TicketBuilder { get; set; }
public HomeController(IServiceProvider service) : base(service) {
this.TicketBuilder = service.GetRequiredService<ITicketBuilder>();
}
3、用户登录。
插件需要自行完成用户认证工作,示例代码如下。
[HttpGet]
public string Login(string username) {
//验证用户有效性,自行调用数据库进行验证。
//如果通过验证,生成用户票据
var user = new UserTicket(
//添加用户名
new Claim("name",username),
//添加其他必要的声明
new Claim("role","admin")
);
var ticket = this.TicketBuilder.GetTicket(user);
return ticket ?? "";
}
客户端在收到返回的票据后自行保管票据。
4、验证用户
实例代码如下:
[HttpGet]
public string ViewUser(string ticket) {
//通过票据获取用户
var cs = this.TicketBuilder.GetUser(ticket);
if(cs == null) {
return "TicketBuilder.GetUser 返回空";
}
StringBuilder sb = new();
//轮训票据生成获取登录信息
foreach(var i in cs.Claims) {
sb.AppendLine($"type:{i.Type},Val:{i.Value}");
}
return sb.ToString();
}
5、绑定用户
示例代码如下:
[HttpGet]
public string Viewbind(string _authUserTicket,[FromHeader] UserTicket user) {
StringBuilder sb = new();
foreach(var i in user.Claims) {
sb.AppendLine($"type:{i.Type},Val:{i.Value}");
}
return sb.ToString();
}
一般客户端通过HTTP头参数_authUserTicket提交用户凭据,这个例子中为了方便通过get参数提交票据,控制器可以自动将其绑定在UserTicket对象中。
因为action还通过httpbody获取了一个_authUserTicket参数,所以UserTicket需要加[FromHeader]特性。
完成以上工作基本就可以正常使用了,但是有时候我们还有一些特殊需求,可以通过下面的方式自行扩展。
6、自定义ClaimTicket配置
通过ClaimTicketOptions对象完成配置。完成配置的途径有两个。
1、在插件配置中优先注入自己的ClaimTicketOptions对象。
public class ServicePlugin:IServicePlugin { IServiceCollection IServicePlugin.AddServices(IServiceCollection services,IConfiguration configuration) { //注入使用ClaimTicket的控制器 services.AddPluginsController(this.GetType().Assembly); //优先添加自己的服务配置 services.AddSingleton(new ClaimTicketOptions()); //添加ClaimTicket服务支持 services.AddClaimTicket(); return services; } }
2、在services.AddClaimTicket中重写ClaimTicketOptions。
public class ServicePlugin:IServicePlugin { IServiceCollection IServicePlugin.AddServices(IServiceCollection services,IConfiguration configuration) { //注入使用ClaimTicket的控制器 services.AddPluginsController(this.GetType().Assembly); //优先添加自己的服务配置 //services.AddSingleton(new ClaimTicketOptions()); //添加ClaimTicket服务支持 services.AddClaimTicket(optionsBuilder => { //客户端通过_headCalimTick属性提交凭据 optionsBuilder.HttpHeaderKey = "_headCalimTick"; }); return services; } }
7、扩展ITicketBuilder
插件可以自行扩展票据的生成方式,方法有两个,一个是继承TicketBuilder对象并重写方法,另一个就是自己实现ITicketBuilder接口。
/// <summary>
/// 自定义票据生成方式
/// </summary>
public class MyTicketBuilder:TicketBuilder, ITicketBuilder
{
/// <summary>
/// 使用票据参数构造生成器
/// </summary>
/// <param name="options">生成参数</param>
public MyTicketBuilder(ClaimTicketOptions options) : base(options) { }
/// <inheritdoc/>
public override string? GetTicket(UserTicket userTicket) {
//实现自己的票据生成方法
//或使用基类提供的方法
return base.GetTicket(userTicket);
}
/// <inheritdoc/>
public override UserTicket? GetUser(string ticket) {
//根据票据获取用户声明返回用户信息
//或使用基类提供的方法
return base.GetUser(ticket);
}
}
然后在调用AddClaimTicket之前注入自己的ITicketBuilder
public class ServicePlugin:IServicePlugin
{
IServiceCollection IServicePlugin.AddServices(IServiceCollection services,IConfiguration configuration) {
//注入使用ClaimTicket的控制器
services.AddPluginsController(this.GetType().Assembly);
//优先添加自己的服务配置
//services.AddSingleton(new ClaimTicketOptions());
//注入扩展MyTicketBuilder
services.TryAddSingleton<ITicketBuilder,MyTicketBuilder>();
//添加ClaimTicket服务支持
services.AddClaimTicket(optionsBuilder => {
//客户端通过_headCalimTick属性提交凭据
optionsBuilder.HttpHeaderKey = "_headCalimTick";
});
return services;
}
}
8、扩展UserTicket
从UserTicket继承实现自己的用户类,比如以下代码实现了自己的MyUserTicket类,并添加了一个Ver属性。
public class MyUserTicket:UserTicket
{
public MyUserTicket() {}
public int Ver { get; set; }
public MyUserTicket(UserTicket? user) {
this.Claims = user?.Claims;
}
}
然后还需要实现自己的ITicketBuilder实现,因为UserTicket不知道如何处理Ver。
/// <summary>
/// 自定义票据生成方式
/// </summary>
public class MyTicketBuilder:TicketBuilder, ITicketBuilder
{
/// <summary>
/// 使用票据参数构造生成器
/// </summary>
/// <param name="options">生成参数</param>
public MyTicketBuilder(ClaimTicketOptions options,IEncryption encryption,IJsonSerialize serialize)
: base(options,encryption,serialize) { }
/// <inheritdoc/>
public override string? GetTicket(UserTicket userTicket) {
//实现自己的票据生成方法
if(userTicket is MyUserTicket mut) {
var obj = mut.Claims.Select(a => new ClaimKeyValue { Key = a.Type,Value = a.Value });
var ll = obj.ToList();
ll.Add(new ClaimKeyValue { Key = "Ver",Value = mut.Ver.ToString() });
var str = this.Serialize.Serialize(ll);
var code = this.Encryption.Encrypt(this.Options.EncryptionKey,str);
return code;
}
//或使用基类提供的方法
return base.GetTicket(userTicket);
}
/// <inheritdoc/>
public override UserTicket? GetUser(string ticket) {
//根据票据获取用户声明返回用户信息
var str = this.Encryption.Decrypt(this.Options.EncryptionKey,ticket);
if(str.IsNullOrEmpty()) {
return new MyUserTicket();
}
var list = this.Serialize.Deserialize<List<ClaimKeyValue>>(str);
if(list == null) {
return new MyUserTicket();
}
var ut = new UserTicket(list.Select(a => new Claim(a.Key,a.Value)));
var result = new MyUserTicket(ut);
var verf = list.Find(a => a.Key == "Ver");
if(verf != null) {
result.Ver = int.Parse(verf.Value);
}
//或使用基类提供的方法
return result as UserTicket;
}
}
然后使用上面的方式把ITicketBuilder注入服务。
接着就是在登录时候使用自己的票据类
public string Login(string username) {
//验证用户密码有效性,自行调用数据库进行验证。
//如果通过验证,生成用户票据
var user = new UserTicket(
//添加用户名
new Claim("name",username),
//添加其他必要的声明
new Claim("role","admin")
);
var muser = new MyUserTicket(user);
//设置自己的特有属性
muser.Ver = 5;
var ticket = this.TicketBuilder.GetTicket(muser);
return ticket ?? "";
}
使用的时候可以直接注入:
public string Viewbind(string _authUserTicket,[FromHeader] MyUserTicket? user) {
if(user == null) {
return "绑定失败!";
}
StringBuilder sb = new();
foreach(var i in user.Claims) {
sb.AppendLine($"type:{i.Type},Val:{i.Value}");
}
sb.AppendLine($"user.Ver={user.Ver}");
return sb.ToString();
}