首页后端开发ASP.NETASP.NET Core的Data Protect(数据保护)的学习和应用

ASP.NET Core的Data Protect(数据保护)的学习和应用

时间2023-12-03 03:11:02发布访客分类ASP.NET浏览617
导读:转载请注入出处: https://home.cnblogs.com/u/zhiyong-ITNote/dotnet core中提供了一个新的身份验证框架Identity,它不同于dot net下的身份验证。在这个框架里面,有一个生成toke...

转载请注入出处: https://home.cnblogs.com/u/zhiyong-ITNote/

dotnet core中提供了一个新的身份验证框架Identity,它不同于dot net下的身份验证。在这个框架里面,有一个生成token的功能,也就是我们常说的令牌,令牌的作用有哪些? Token值介绍 token 值: 登录令牌.利用 token 值来判断用户的登录状态.类似于 MD5 加密之后的长字符串. 用户登录成功之后,在后端(服务器端)会根据用户信息生成一个唯一的值.这个值就是 token 值. 基本使用: 在服务器端(数据库)会保存这个 token 值,以后利用这个 token 值来检索对应的用户信息,并且判断用户的登录状态. 用户登录成功之后,服务器会将生成的 token 值返回给 客户端,在客户端也会保存这个 token 值.(一般可以保存在 cookie 中,也可以自己手动确定保存位置(比如偏好设置.)). 以后客户端在发送新的网络请求的时候,会默认自动附带这个 token 值(作为一个参数传递给服务器.).服务器拿到客户端传递的 token 值跟保存在 数据库中的 token 值做对比,以此来判断用户身份和登录状态. 判断登录状态: 如果客户端没有这个 token 值,意味着没有登录成功过,提示用户登录. 如果客户端有 token 值,一般会认为登录成功.不需要用户再次登录(输入账号和密码信息). token 值扩展: token 值有失效时间: 一般的 app ,token值得失效时间都在 1 年以上. 特殊的 app :银行类 app /支付类 app :token值失效时间 15 分钟左右. 一旦用户信息改变(密码改变),会在服务器生成新的 token 值,原来的 token值就会失效.需要再次输入账号和密码,以得到生成的新的 token 值. 唯一性判断: 每次登录,都会生成一个新的token值.原来的 token 值就会失效.利用时间来判断登录的差异性.

至此也就说完了其作用。那么Identity框架是如何为我们提供这个能力的呢?我们又该如何使用呢?首先请你看下 asp.net core中的数据保护模块,这是Identity框架实现token的基础。 var token = await userManager.GenerateUserTokenAsync(user, "Default", "passwordless-auth"); 我们通过这句代码来生成token,userManager是Identity框架的用户管理类UserManager的实例对象。

当然首先我们需要实现相关的依赖注入,我就不说了。Identity默认生成的token是基于DataProtectorTokenProvider类的,我们在依赖注入的时候,其实就引用了这个类,先看下AddDefaultTokenProviders的源码:

public static IdentityBuilder AddDefaultTokenProviders(this IdentityBuilder builder)
{
    
var userType = builder.UserType;
    
var dataProtectionProviderType = typeof(DataProtectorTokenProvider>
    ).MakeGenericType(userType);
    
var phoneNumberProviderType = typeof(PhoneNumberTokenProvider>
    ).MakeGenericType(userType);
    
var emailTokenProviderType = typeof(EmailTokenProvider>
    ).MakeGenericType(userType);
    
var authenticatorProviderType = typeof(AuthenticatorTokenProvider>
    ).MakeGenericType(userType);
    
return builder.AddTokenProvider(TokenOptions.DefaultProvider, dataProtectionProviderType)
.AddTokenProvider(TokenOptions.DefaultEmailProvider, emailTokenProviderType)
.AddTokenProvider(TokenOptions.DefaultPhoneProvider, phoneNumberProviderType)
.AddTokenProvider(TokenOptions.DefaultAuthenticatorProvider, authenticatorProviderType);

}
    

然后我们看下DataProtectorTokenProvider类的部分源码:

public class DataProtectorTokenProviderTUser>
     : IUserTwoFactorTokenProviderTUser>
 where TUser : class
{
    
/// summary>

/// Initializes a new instance of the see cref="DataProtectorTokenProvider{
TUser}
    "/>
     class.
/// /summary>
    
/// param name="dataProtectionProvider">
    The system data protection provider./param>
    
/// param name="options">
    The configured see cref="DataProtectionTokenProviderOptions"/>
    ./param>
    
public DataProtectorTokenProvider(IDataProtectionProvider dataProtectionProvider, IOptionsDataProtectionTokenProviderOptions>
 options)
{

if (dataProtectionProvider == null)
{
    
throw new ArgumentNullException(nameof(dataProtectionProvider));

}
    
Options = options?.Value ?? new DataProtectionTokenProviderOptions();
    
// Use the Name as the purpose which should usually be distinct from others
Protector = dataProtectionProvider.CreateProtector(Name ?? "DataProtectorTokenProvider");
 
}
    

public virtual async Taskstring>
     GenerateAsync(string purpose, UserManagerTUser>
 manager, TUser user)
{

if (user == null)
{
    
throw new ArgumentNullException(nameof(user));

}
    
var ms = new MemoryStream();
    
var userId = await manager.GetUserIdAsync(user);

using (var writer = ms.CreateWriter())
{
    
writer.Write(DateTimeOffset.UtcNow);
    
writer.Write(userId);
    
writer.Write(purpose ?? "");
    
string stamp = null;

if (manager.SupportsUserSecurityStamp)
{
    
stamp = await manager.GetSecurityStampAsync(user);

}
    
writer.Write(stamp ?? "");

}
    
var protectedBytes = Protector.Protect(ms.ToArray());
    
return Convert.ToBase64String(protectedBytes);

}
    
public virtual async Taskbool>
     ValidateAsync(string purpose, string token, UserManagerTUser>
 manager, TUser user)
{

try
{
    
var unprotectedData = Protector.Unprotect(Convert.FromBase64String(token));
    
var ms = new MemoryStream(unprotectedData);

using (var reader = ms.CreateReader())
{
    
var creationTime = reader.ReadDateTimeOffset();
    
var expirationTime = creationTime + Options.TokenLifespan;

if (expirationTime  DateTimeOffset.UtcNow)
{
    
return false;

}
    

var userId = reader.ReadString();
    
var actualUserId = await manager.GetUserIdAsync(user);

if (userId != actualUserId)
{
    
return false;

}
    
var purp = reader.ReadString();

if (!string.Equals(purp, purpose))
{
    
return false;

}
    
var stamp = reader.ReadString();

if (reader.PeekChar() != -1)
{
    
return false;

}


if (manager.SupportsUserSecurityStamp)
{
    
return stamp == await manager.GetSecurityStampAsync(user);

}
    
return stamp == "";

}

}

// ReSharper disable once EmptyGeneralCatchClause
catch
{

// Do not leak exception
}
    
return false;

}

}

可以看到,默认的情况下,使用的就是asp.net core Data Provider生成token的。我们来看看这个DataProtectorTokenProviderOptions配置类的信息:

public class DataProtectionTokenProviderOptions
{

public string Name {
     get;
     set;
 }
     = "DataProtectorTokenProvider";


public TimeSpan TokenLifespan {
     get;
     set;
 }
     = TimeSpan.FromDays(1);

}
    

默认的情况下,token过期时间是一天,也就是说,如果我们需要修改过期时间的话,完全可以自己来:

services.ConfigureDataProtectionTokenProviderOptions>
    (
x =>
     x.TokenLifespan = TimeSpan.FromMinutes(15));
    

刚刚也说了,默认情况下Identity框架给我们提供的token是基于Data Protect的,那么我们可以切换另外的token提供方式。只需继承自TotpSecurityStampBasedTokenProviderTUser> 类就可以了。该类源码地址: https://github.com/aspnet/Identity/blob/c7276ce2f76312ddd7fccad6e399da96b9f6fae1/src/Core/TotpSecurityStampBasedTokenProvider.cs#L21 该类与DataProtectorTokenProvider类一样都是继承自IUserTwoFactorTokenProvider接口来实现的,其方法都是一样的,只是该类的token生成算法不再是Data Protect中的token生成算法了,而是hash算法,因此这里也是一个可拓展点,我们还可以提供自己的想要的加密算法来生成token。

public class PasswordlessLoginTotpTokenProviderTUser>
     : TotpSecurityStampBasedTokenProviderTUser>
 
where TUser : class
{
    
public override Taskbool>
     CanGenerateTwoFactorTokenAsync(UserManagerTUser>
 manager, TUser user)
{
    
return Task.FromResult(false);

}
    

public override async Taskstring>
     GetUserModifierAsync(string purpose, UserManagerTUser>
 manager, TUser user)
{
    
var email = await manager.GetEmailAsync(user);
    
return "PasswordlessLogin:" + purpose + ":" + email;

}

}


public static class CustomIdentityBuilderExtensions 
{

public static IdentityBuilder AddPasswordlessLoginTotpTokenProvider(this IdentityBuilder builder)
{
    
var userType = builder.UserType;
    
var totpProvider = typeof(PasswordlessLoginTotpTokenProvider>
    ).MakeGenericType(userType);
    
return builder.AddTokenProvider("PasswordlessLoginTotpProvider", totpProvider);

}

}


public void ConfigureServices(IServiceCollection services)
{
    
services.AddIdentityIdentityUser, IdentityRole>
    ()
.AddEntityFrameworkStoresIdentityDbContext>
    () 
.AddDefaultTokenProviders()
.AddPasswordlessLoginTotpTokenProvider();
 // Add the custom token provider
}
    


var token = await userManager.GenerateUserTokenAsync( 
user, "PasswordlessLoginTotpProvider", "passwordless-auth");
    

这就是我们的使用了。在这里提一下。TotpSecurityStampBasedTokenProvider类的默认生命周期是9分钟,一旦超过9分钟,token就会变化。

大概的理了下自己接下来的实现需要用到的技术,不能为了实现而实现,而是要想清楚需要的技术,同时去学习这些技术,然后再去实现。其实这个需求是我自己加的,因为之前看官方文档的时候,对数据保护很懵逼,只知道可以用来生成token加密,却不知道实际的用途,因此自己深入研究查找资料,借鉴别人的博客来学习,还是google好啊,百度真...就不爆粗口了。 整理下自己需要实现得需求思路: 我们可以在邮箱验证的时候用到token,也可以在整个的网站中用到,第一个就先不说了,说说第二个: 我们一般可以将用户登陆之后,根据用户名什么的生成token,然后放到服务端也就是数据库了,我们给它有效期(比如连续记住我十天之类的)表示这个用户已经登录过了。那么客户端呢?也就是我们的浏览器,我们可以将cookie存入客户端浏览器,但是一旦我们关闭了浏览器那么cookie也就不存在了,因此不可行。可以存入到本地磁盘中。同时,一般来讲,网站的url都很长,一般都是将token拼接在了url里面,如果你觉得url太长了,我们可以在中间件中写入到http头部字段中,根据http头部字段。当然你可以在ActionFilter以及ResultFilter中写入http头部。

回头看看能不能整理出来一个实现,到时候再放上来代码。

参考资料: Implementing custom token providers for passwordless authentication in ASP.NET Core Identity

Implementing Medium's Passwordless Authentication using ASP.NET Core Identity

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!


若转载请注明出处: ASP.NET Core的Data Protect(数据保护)的学习和应用
本文地址: https://pptw.com/jishu/565634.html
asp.net core下的如何给网站做安全设置 asp.net core自定义模型验证——前端验证

游客 回复需填写必要信息