283 lines
8.4 KiB
Markdown
283 lines
8.4 KiB
Markdown
## 客户凭据 Falcon.SugarApi.ClaimTicket.ClaimTicket
|
||
|
||
### 1、添加ClaimTicket支持。
|
||
是否使用ClaimTicket由插件自行决定。
|
||
如果插件需要使用ClaimTicket,按如下方式在插件服务配置中添加。
|
||
~~~C#
|
||
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的示例。
|
||
~~~C#
|
||
|
||
public ITicketBuilder TicketBuilder { get; set; }
|
||
|
||
public HomeController(IServiceProvider service) : base(service) {
|
||
this.TicketBuilder = service.GetRequiredService<ITicketBuilder>();
|
||
}
|
||
~~~
|
||
### 3、用户登录。
|
||
插件需要自行完成用户认证工作,示例代码如下。
|
||
~~~c#
|
||
[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、验证用户
|
||
实例代码如下:
|
||
~~~c#
|
||
[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、绑定用户
|
||
示例代码如下:
|
||
~~~c#
|
||
[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对象。
|
||
> ~~~c#
|
||
> 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。
|
||
> ~~~c#
|
||
> 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接口。
|
||
|
||
~~~c#
|
||
/// <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
|
||
~~~c#
|
||
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属性。
|
||
~~~c#
|
||
public class MyUserTicket:UserTicket
|
||
{
|
||
public MyUserTicket() {}
|
||
|
||
public int Ver { get; set; }
|
||
|
||
public MyUserTicket(UserTicket? user) {
|
||
this.Claims = user?.Claims;
|
||
}
|
||
}
|
||
~~~
|
||
然后还需要实现自己的ITicketBuilder实现,因为UserTicket不知道如何处理Ver。
|
||
~~~c#
|
||
/// <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注入服务。
|
||
接着就是在登录时候使用自己的票据类
|
||
~~~c#
|
||
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 ?? "";
|
||
}
|
||
|
||
~~~
|
||
使用的时候可以直接注入:
|
||
~~~c#
|
||
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();
|
||
}
|
||
~~~
|