Asp.net core 学习笔记 ( Identity 之 Authentication )
和从前的 identity 区别不是很大.
从 2.1 开始 vs 模板的 identity 都被封装了起来, 你几乎看不到任何一行代码, 需要向下面这样打开它, 才能做修改.
说一下比较常用的配置
services.Configure<DataProtectionTokenProviderOptions>(
x => x.TokenLifespan = TimeSpan.FromHours()); services.AddDefaultIdentity<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedEmail = false;
options.SignIn.RequireConfirmedPhoneNumber = false;
//options.Tokens.EmailConfirmationTokenProvider = "MyEmailTokenProvider"; options.Lockout.AllowedForNewUsers = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes();
options.Lockout.MaxFailedAccessAttempts = ; options.Password.RequireDigit = false;
options.Password.RequiredLength = ;
options.Password.RequiredUniqueChars = ;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false; options.User.RequireUniqueEmail = true;
})
.AddSecurityPhoneTokenProvider()
.AddRoles<ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
TokenLifespan 是说在 reset password 之类的情况, token 的时长. options.Lockout 就是说如果用户多次尝试 password login 账号会被锁起来, 防止暴力破解密码.
options.Password 就是 password 强度
AddSecurityPhoneTokenProvider 是我自己写的一个东西. 随便说一下吧. 在做 reset password 时, identity 默认会生成一个很长的 token, 这个叫 DefaultTokenProvider, 时长就是 TokenLefespan,
不过这种长 token 只适合使用 email + link 的方式来 reset password
如果用户没有 email 只有手机号, 那就不管用了.
好在 identity 也有比较短的 token 适合手机的, 叫 totp (time based on time password)
原理是使用当前时间+密钥+算法来生成 token, 不过这个其实是用在 2fa 的, 并不适合用于 reset password.
因为这种 token 默认可以保持 3 分钟, 可以无限尝试. 很容易暴力破解.
identity 默认的 phoneConfirm 就是用这个方式的.
但是对我来说还不够安全, 所以我自己加了一个扩展, 通过数据库记入尝试次数, 防止暴力破解.
public static class IdentityBuilderExtensions
{
public static IdentityBuilder AddSecurityPhoneTokenProvider(this IdentityBuilder builder)
{
var userType = builder.UserType;
var provider = typeof(SecurityPhoneNumberTokenProvider<>).MakeGenericType(userType);
return builder.AddTokenProvider(TokenOptions.SecurityPhoneProvider, provider);
}
} //public static class ClaimsPrincipalExtensions
//{
// public static int GetUserId(this ClaimsPrincipal principal)
// {
// if (principal == null) throw new ArgumentNullException(nameof(principal));
// var stringId = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
// if (stringId == null) throw new Exception("User Id not found in claim");
// return Convert.ToInt32(stringId);
// }
//} public class TokenOptions
{
public static readonly string SecurityPhoneProvider = "SecurityPhone";
} public class SecurityPhoneNumberTokenProvider<TUser> : PhoneNumberTokenProvider<TUser> where TUser : ApplicationUser
{
private const int MaxFailedCount = ;
private const int TokenExpiryInMinutes = ;
private ApplicationDbContext Db { get; set; } public SecurityPhoneNumberTokenProvider(ApplicationDbContext db)
{
Db = db;
} public override async Task<string> GenerateAsync(string purpose, UserManager<TUser> manager, TUser user)
{
var token = await base.GenerateAsync(purpose, manager, user);
Db.UserSecurityTokens.Add(new UserSecurityToken
{
userId = user.Id,
token = token
});
await Db.SaveChangesAsync();
return token;
} public override async Task<bool> ValidateAsync(string purpose, string token, UserManager<TUser> manager, TUser user)
{
var ok = await base.ValidateAsync(purpose, token, manager, user);
if (ok)
{
var userToken = await Db.UserSecurityTokens.FirstOrDefaultAsync(u => u.userId == user.Id && u.token == token);
return userToken.failedCount <= MaxFailedCount;
}
else
{
var userTokens = await Db.UserSecurityTokens.Where(u => u.userId == user.Id).ToListAsync();
foreach (var userToken in userTokens)
{
if (userToken.rowCreated.AddMinutes(TokenExpiryInMinutes) <= DateTime.Now)
{
Db.UserSecurityTokens.Remove(userToken);
}
else
{
userToken.failedCount++;
}
}
await Db.SaveChangesAsync();
return false;
}
}
}
支持第三方登入
services.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = "xx";
options.ClientSecret = "yy";
options.Events.OnCreatingTicket = (context) =>
{
context.Identity.AddClaim(new Claim("image", context.User.GetValue("image").SelectToken("url").ToString()));
context.Identity.AddClaim(new Claim("gender", context.User.GetValue("gender").ToString()));
context.Identity.AddClaim(new Claim("language", context.User.GetValue("language").ToString()));
var g = context.User.GetValue("whatever"); // null
return Task.CompletedTask;
};
})
通过 onCreatingTicket 可以把资料放入特定的 claim 中, 比如 accessToken 等.
facebook 的比较麻烦
.AddFacebook(options =>
{
// app setup https://developers.facebook.com/apps/482615952162581/settings/basic/
// user remove fb login https://facebook.com/settings?tab=applications
// scope https://developers.facebook.com/docs/facebook-login/permissions/#reference-default_fields
// field https://developers.facebook.com/docs/graph-api/reference/v2.2/user
options.ClientId = "xx";
options.ClientSecret = "yy";
options.Scope.Add("email");
options.Scope.Add("user_gender");
options.Scope.Add("user_age_range");
options.Scope.Add("user_birthday");
options.Scope.Add("user_location");
options.Fields.Add("picture");
options.Fields.Add("email");
options.Fields.Add("gender");
options.Fields.Add("age_range");
options.Fields.Add("birthday");
options.Fields.Add("location"); options.Events.OnRedirectToAuthorizationEndpoint = (context) =>
{
// auth_type=rerequest 可以再次要求 scope (它很聪明的, 如果 scope 都 allow 了是不会 rerequest 的)
var rerequestQueryParams = new Dictionary<string, string> { { "auth_type", "rerequest" } };
var newUri = QueryHelpers.AddQueryString(context.RedirectUri, rerequestQueryParams);
context.HttpContext.Response.Redirect(newUri);
return Task.CompletedTask;
};
options.Events.OnCreatingTicket = (context) =>
{
var x = context.User;
//context.Identity.AddClaim(new Claim("image", context.User.GetValue("image").SelectToken("url").ToString()));
//context.Identity.AddClaim(new Claim("gender", context.User.GetValue("gender").ToString()));
//context.Identity.AddClaim(new Claim("language", context.User.GetValue("language").ToString()));
//var g = context.User.GetValue("whatever"); // null
return Task.CompletedTask;
};
});
通过 scope 和 fields 添加更多的资料. rerequest 用于再次要求额外 scope .
更灵活的 facebook 图片获取 https://stackoverflow.com/questions/11442442/get-user-profile-picture-by-id
最后通过 controller 通过 signInMangager 获取 claim 就可以了.
var info = await _signInManager.GetExternalLoginInfoAsync();
string email = info.Principal.FindFirstValue(ClaimTypes.Email);
Asp.net core 学习笔记 ( Identity 之 Authentication )的更多相关文章
- Asp.net core 学习笔记 ( identity server 4 JWT Part )
更新 : id4 使用这个 DbContext 哦 dotnet ef migrations add identity-server-init --context PersistedGrantDbCo ...
- Asp.Net Core学习笔记:入门篇
Asp.Net Core 学习 基于.Net Core 2.2版本的学习笔记. 常识 像Django那样自动检查代码更新,自动重载服务器(太方便了) dotnet watch run 托管设置 设置项 ...
- ASP.NET Core 身份认证 (Identity、Authentication)
Authentication和Authorization 每每说到身份验证.认证的时候,总不免说提及一下这2个词.他们的看起来非常的相似,但实际上他们是不一样的. Authentication想要说明 ...
- ASP.NET Core 学习笔记 第一篇 ASP.NET Core初探
前言 因为工作原因博客断断续续更新,其实在很早以前就有想法做一套关于ASP.NET CORE整体学习度路线,整体来说国内的环境的.NET生态环境还是相对比较严峻的,但是干一行爱一行,还是希望更多人加入 ...
- Asp.net core 学习笔记 (授权)
更新 : 2018-11-24 记入一些思考 asp.net core + identity 的权限是这样的 user = 1 个登入账号 role = 1 个角色 (类似于公司里的一个职位) cla ...
- Asp.net Core学习笔记
之前记在github上的,现在搬运过来 变化还是很大的,感觉和Nodejs有点类似,比如中间件的使用 ,努力学习ing... 优点 不依赖IIS 开源和跨平台 中间件支持 性能优化 无所不在的依赖注入 ...
- ASP.NET Core 学习笔记 第三篇 依赖注入框架的使用
前言 首先感谢小可爱门的支持,写了这个系列的第二篇后,得到了好多人的鼓励,也更加坚定我把这个系列写完的决心,也能更好的督促自己的学习,分享自己的学习成果.还记得上篇文章中最后提及到,假如服务越来越多怎 ...
- ASP.NET Core 学习笔记 第四篇 ASP.NET Core 中的配置
前言 说道配置文件,基本大多数软件为了扩展性.灵活性都会涉及到配置文件,比如之前常见的app.config和web.config.然后再说.NET Core,很多都发生了变化.总体的来说技术在进步,新 ...
- ASP.NET Core 学习笔记 第五篇 ASP.NET Core 中的选项
前言 还记得上一篇文章中所说的配置吗?本篇文章算是上一篇的延续吧.在 .NET Core 中读取配置文件大多数会为配置选项绑定一个POCO(Plain Old CLR Object)对象,并通过依赖注 ...
随机推荐
- oracle查询所有初始化参数(含隐含参数)
年龄大了,感觉记性不是很好了,还是重新做笔记了.最近在整理些稿子,顺便在记录下oracle查询所有初始化参数(含隐含参数): SELECT i.ksppinm name, i.ksppdesc des ...
- 错误 1 error LNK2019: 无法解析的外部符号 __imp__pthread_create,该符号在函数 _main 中被引用 解决方法
晚上花几分钟在windows下测了下pthread的用法,出现错误 1 error LNK2019: 无法解析的外部符号 __imp__pthread_create,该符号在函数 _main 中被引用 ...
- phpstorm激活大全--持续更新(支持2018最新版)
方法一. 通过Licence Server 激活PHPStorm(快速) 方法原理是通过搭建服务器激活,不过网上有许多搭建好的. http://idea.goxz.gq http://v2mc.net ...
- 【TensorFlow】tf.nn.max_pool实现池化操作
max pooling是CNN当中的最大值池化操作,其实用法和卷积很类似 有些地方可以从卷积去参考[TensorFlow]tf.nn.conv2d是怎样实现卷积的? tf.nn.max_pool(va ...
- 创建一个maven项目
创建父工程 1.新建maven project,点击next 2.默认配置,点击next 3.默认配置,点击next 4.填写Group Id一般采用域名倒写,Artifact Id为项目名称.然后点 ...
- Ubuntu18.04 安装搜狗输入法后无法启动的问题
ibus 改选成fcitx后搜狗输入法照样没出来. 这里需要im-config 没有的话需要安装: sudo apt install im-config 然后在Terminal中执行 im-confi ...
- 【ASP.NET】System.Web.Routing - HttpMethodConstraint Class
你可以自己定义你的ASP.NET程序接收的get post put 或者delete请求. 使用这个约束的方式为: void Application_Start(object sender, Even ...
- 用Qemu模拟vexpress-a9 --- 配置 qemu 的网络功能
转载:http://wiki.sylixos.com/index.php/Linux%E7%8E%AF%E5%A2%83%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97 环境介 ...
- demoshow - webdemo展示助手
demoshow - web demo展示助手 动态图演示页面: http://www.cnblogs.com/daysme/p/6790829.html 一个用来展示前端网页demo的小“助手”,提 ...
- web前端知识总结
前言: 一直想着整理一下关于前端的知识体系和资料,工作忙了些,挤挤总会有的,资料很多,就看你能不能耐下心坚持去学了,要多学多敲多想,祝你进步~ 学习之前首先要大概了解什么是HTML ,CSS , JS ...