100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Asp.net core Identity + identity server + angular 学习笔记 (第一篇)

Asp.net core Identity + identity server + angular 学习笔记 (第一篇)

时间:2023-01-10 22:35:21

相关推荐

Asp.net core Identity + identity server + angular 学习笔记 (第一篇)

用了很长一段时间了, 但是一直没有做过任何笔记,感觉 identity 太多东西要写了, 提不起劲. 但是时间一久很多东西都记不清了.

还是写一轮吧. 加深记忆.

这是 0-1 的笔记, 会写好多篇. 写的时候是没有提前设计流程, 所以如果你把它当教程来看是不太妥当的,要读就必须一篇一篇顺着读,间中还会有错误和修正, 请小心.

identity 就是做登入授权的一个架构, core 自带的. 因为大部分项目都会需要有登入授权机制.

identity server 之后才会提到.

虽然 identity 有自带的 ui 模板,但是为了比较清楚我们还是从一个空白的项目开始吧.

开启 vs 创建一个 razor page 项目.

首先, 我们来做一些基本 setup. identity 需要有一个 sql 储存, 我们就使用 ef core + local sql server (vs 自带) 吧.

如果你不熟悉 ef core 可以看这里/en-us/aspnet/core/data/ef-mvc/intro?view=aspnetcore-2.2

先创建一个 DbContext 并继承IdentityDbContext

namespace Project.Entity{public class ApplicationDbContext : IdentityDbContext<IdentityUser>{public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options){}}}

IdentityDbContext 封装了所有 identity 需要的 tables, 比如 user, role, claim 等等...

添加 default connection string config 在appsettings.json.

"ConnectionStrings": {"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=identity;Trusted_Connection=True;MultipleActiveResultSets=true"}

添加 service 到 startup.cs

services.AddDbContext<ApplicationDbContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

数据库弄好了以后我们来弄 identity service

identity 给了我们一个AddDefaultIdentity 的便利

services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<ApplicationDbContext>();

但是这个是配合 default ui 的, 我们直接用比较底层的功能 .

参考源码/aspnet/AspNetCore/blob/release/2.2/src/Identity/UI/src/IdentityServiceCollectionUIExtensions.cs#L47-L63

services.AddAuthentication(o =>{o.DefaultScheme = IdentityConstants.ApplicationScheme;o.DefaultSignInScheme = IdentityConstants.ExternalScheme;}).AddIdentityCookies(o => { });services.AddIdentityCore<IdentityUser>(o =>{o.Stores.MaxLengthForKeys = 128;}).AddDefaultTokenProviders().AddEntityFrameworkStores<ApplicationDbContext>();services.ConfigureApplicationCookie(options =>{options.LoginPath = "/Login";});

从源码抄过来, 省略掉.AddDefaultUI() 就可以了.

这里还多了一个ConfigureApplicationCookie, 我设定了一个登入页面路径, 当用户访问一个权限页面的时候就会被自动跳转到登入页面.

identtiy 还可以配置很多 config, 之后才说.

到这里, services 算是弄好了. 我们来弄 AppConfig, 添加 app.UseAuthentication() 就可以了

app.UseCookiePolicy();app.UseAuthentication(); // 加入这个app.UseMvc(routes =>{routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");});

startup.cs 完成. 我们现在去创建 2 个 razor page. 一个 About, 一个 Login

然后在 About.cshtml.cs 里做一个权限访问.

[Authorize]public class AboutModel : PageModel{public void OnGet(){}}

在到 home page 做一个 <a> 访问 about page

home page <a asp-page="About" >about</a>

当我们访问 about 时, 就会被跳转到 login 页面了。

目前我们还没有任何账号可以登入,必须先有一个 register 的功能.

这时就会用到数据库了. 刚才我们做了配置但是并还没有生成数据库

我们使用 ef core migrations 来完成这个事情, 如果你不熟悉这个请先看这里

/en-us/ef/core/managing-schemas/migrations/

运行 command

dotnet ef migrations add init

dotnet ef database update

搞定!

接下来就是做一个 register form 我们直接在 login page 里头做就好了.

Register form<form asp-page="Login" asp-page-handler="Login"><input type="text" name="username" placeholder="username"><input type="password" name="password" placeholder="password"><button type="submit">Login</button></form>

同时在 Login.cshtml.cs 也做一个 handler

public class LoginInputModel{public string username { get; set; }public string password { get; set; }}[BindProperty]public LoginInputModel LoginData { get; set; }public async Task OnPostLoginAsync([FromServices] UserManager<IdentityUser> userManager){var user = new IdentityUser{UserName = LoginData.username};var reuslt = await userManager.CreateAsync(user, LoginData.password);if (reuslt.Succeeded){}}

使用 userManager service 来替我们服务. 这是 identity 封装的服务.

这个小功能里头做了不少事儿...

比如 :

检查 password 格式 (不能少于 6 个字啦... 要有大写啦... 等等等, 这个我们是可以配置的, 等下会讲)

检查 username 格式对不对 (有些时候 username 不能包含默写字符串或者符号等, 这个也是可以配置的, 等下讲)

检查 username duplicate,或者 email duplicate (username 一定是 unique, email 则可以配置要不要 unique,之后会讲)

hash password, 我们都知道用户的 password 不可以明文保存在数据库 ( 如果你不知道可以上网搜搜, 比如/group/topic/26022844/)

这里 hash password 就涉及到 md5, sha256, 盐等等密码学的知识了. identity 就是为我们处理了这些事儿, 省心吧.

最后就是入库啦.

如果你按照目前的代码运行,并且输入

username = "``"

password = "``"

result 会出现 error, 因为 identity 默认对 password 蛮严格的,还有 username 也是有指定的字符串.

我们现在就去调整它. 当 startup.cs 的 service 调整 options

如果你对 options 的使用不熟悉,可以看这里/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.2

services.Configure<IdentityOptions>(options =>{// Password settings.options.Password.RequireDigit = false;options.Password.RequireLowercase = false;options.Password.RequireNonAlphanumeric = false;options.Password.RequireUppercase = false;options.Password.RequiredLength = 0;options.Password.RequiredUniqueChars = 0;// User settings.options.User.AllowedUserNameCharacters = null; // 默认是 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+"; null 表示啥都行options.User.RequireUniqueEmail = false;});

这样就完全没有限制了.

有人喜欢无拘无束,有人不喜欢.

如果我们反而嫌 identity 的 password valid 还不够多呢?

比如, 我要求, password 不可以和 username 相等. 这个怎么实现呢 ?

identity 为我们开放了扩展

首先写一个 validator class 实现接口IPasswordValidator

public class MyPasswordValidator : IPasswordValidator<IdentityUser>{public Task<IdentityResult> ValidateAsync(UserManager<IdentityUser> manager, IdentityUser user, string password){if (user.UserName.Equals(password, StringComparison.OrdinalIgnoreCase)){var result = IdentityResult.Failed(new IdentityError{Code = "PasswordSameAsUsername",Description = "password can't same as username."});return Task.FromResult(result);} return Task.FromResult(IdentityResult.Success);}}

里面可以使用依赖注入获取我们要的任何服务, 如果你的验证需要用数据库, 用 HttpClient 都是可以的.

然后呢,我们把这个 validator 添加进 identity 里头, 到 startup.cs 的 service 里弄

services.AddIdentityCore<IdentityUser>(o =>{o.Stores.MaxLengthForKeys = 128;}).AddDefaultTokenProviders().AddEntityFrameworkStores<ApplicationDbContext>().AddPasswordValidator<MyPasswordValidator>(); // 加这个

如果有很多个, 也可以一个一个加进去. 并没有限制多少个 validator. 在源码中可以看到, identity 会把所有 validator for loop 来执行 ValidateAsync

user validator 也是类似的实现手法,

创建一个 UserValidator 里面写逻辑

public class MyUserValidator : IUserValidator<IdentityUser>{public Task<IdentityResult> ValidateAsync(UserManager<IdentityUser> manager, IdentityUser user){if (!user.UserName.EndsWith(".my")){var result = IdentityResult.Failed(new IdentityError{Code = "UsernameNotEndsWithStoogesDomain",Description = "username must ends with .my"});return Task.FromResult(result);}return Task.FromResult(IdentityResult.Success);}}

加入 startup.cs service

services.AddIdentityCore<IdentityUser>(o =>{o.Stores.MaxLengthForKeys = 128;}).AddDefaultTokenProviders().AddEntityFrameworkStores<ApplicationDbContext>().AddPasswordValidator<MyPasswordValidator>().AddUserValidator<MyUserValidator>(); // 加这个

搞定 !

这篇总结与回顾 :

- 空白的 razor page

- ef core with identity DbContext setup

- identity setup

- authorize page (about) and login page

- register create user

- password validator

- user validator

github :/keatkeat87/aspnetcore-identity

我的 commit 是依据一篇一篇 turorial 写的,可以 checkout 回去观察。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。