asp.net core系列 47 Identity 自定义用户数据
一.概述
接着上篇的webappidentitydemo项目,将自定义用户数据添加到identity db,自定义扩展的用户数据类应继承identityuser类, 文件名为areas / identity / data / {项目名称}user.cs。自定义的用户数据模型属性需要使用[personaldata]来修饰,以便自动下载和删除。使数据能够下载和删除有助于满足gdpr要求。
1.1 自定义用户数据类 webappidentitydemo.areas.identity.data。
public class webappidentitydemouser:identityuser { /// <summary> /// full name /// </summary> [personaldata] public string name { get; set; } /// <summary> /// birth date /// </summary> [personaldata] public datetime dob { get; set; } }
使用属性修饰personaldata特性是:
使用areas/identity/pages/account/manage/deletepersonaldata.cshtml 页调用usermanager.delete
使用areas/identity/pages/account/manage/downloadpersonaldata.cshtml 页下载用户数据
1.2 修改identityhostingstartup
将startup中有关identity的服务移到该文件中,好集中管理。
public class identityhostingstartup : ihostingstartup { public void configure(iwebhostbuilder builder) { builder.configureservices((context, services) => { services.adddbcontext<applicationdbcontext>(options => options.usesqlserver( context.configuration.getconnectionstring("defaultconnection"))); services.adddefaultidentity<webappidentitydemouser>() .adddefaultui() .addentityframeworkstores<applicationdbcontext>(); services.configure<identityoptions>(options => { // password settings. options.password.requiredigit = true; options.password.requirelowercase = true; options.password.requirenonalphanumeric = true; options.password.requireuppercase = true; options.password.requiredlength = 6; options.password.requireduniquechars = 1; // lockout settings. options.lockout.defaultlockouttimespan = timespan.fromminutes(5); options.lockout.maxfailedaccessattempts = 5; options.lockout.allowedfornewusers = true; // user settings. options.user.allowedusernamecharacters = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789-._@+"; options.user.requireuniqueemail = false; }); services.configureapplicationcookie(options => { // cookie settings options.cookie.httponly = true; options.expiretimespan = timespan.fromminutes(5); options.loginpath = $"/identity/account/login"; options.logoutpath = $"/identity/account/logout"; options.accessdeniedpath = $"/identity/account/accessdenied"; }); }); } }
1.3 修改dbcontext上下文
// public class applicationdbcontext : identitydbcontext public class applicationdbcontext : identitydbcontext<webappidentitydemouser> { public applicationdbcontext(dbcontextoptions<applicationdbcontext> options) : base(options) { } protected override void onmodelcreating(modelbuilder builder) { base.onmodelcreating(builder); // customize the asp.net core identity model and override the defaults if needed. // for example, you can rename the asp.net core identity table names and more. // add your customizations after calling base.onmodelcreating(builder); } }
1.4 数据库版本迁移
pm> add-migration identityschema2 pm> update-database identityschema2
1.5 更新注册页面
在开发中,会员系统要重用修改的页面,把identityuser 改成webappidentitydemouser。如果没改将报错:未解析到服务identityuser。红色部分为修改的代码
[allowanonymous] public class registermodel : pagemodel { // private readonly signinmanager<identityuser> _signinmanager; //private readonly usermanager<identityuser> _usermanager; private readonly signinmanager<webappidentitydemouser> _signinmanager; private readonly usermanager<webappidentitydemouser> _usermanager; private readonly ilogger<registermodel> _logger; private readonly iemailsender _emailsender; public registermodel( usermanager<webappidentitydemouser> usermanager, signinmanager<webappidentitydemouser> signinmanager, ilogger<registermodel> logger, iemailsender emailsender) { _usermanager = usermanager; _signinmanager = signinmanager; _logger = logger; _emailsender = emailsender; } [bindproperty] public inputmodel input { get; set; } public string returnurl { get; set; } public class inputmodel { [required] [datatype(datatype.text)] [display(name = "full name")] public string name { get; set; } [required] [display(name = "birth date")] [datatype(datatype.date)] public datetime dob { get; set; } [required] [emailaddress] [display(name = "email")] public string email { get; set; } [required] [stringlength(100, errormessage = "the {0} must be at least {2} and at max {1} characters long.", minimumlength = 6)] [datatype(datatype.password)] [display(name = "password")] public string password { get; set; } [datatype(datatype.password)] [display(name = "confirm password")] [compare("password", errormessage = "the password and confirmation password do not match.")] public string confirmpassword { get; set; } } public void onget(string returnurl = null) { returnurl = returnurl; } public async task<iactionresult> onpostasync(string returnurl = null) { returnurl = returnurl ?? url.content("~/"); if (modelstate.isvalid) { // var user = new identityuser { username = input.email, email = input.email }; var user = new webappidentitydemouser { username = input.email, email = input.email, name = input.name, dob = input.dob }; var result = await _usermanager.createasync(user, input.password); if (result.succeeded) { _logger.loginformation("user created a new account with password."); var code = await _usermanager.generateemailconfirmationtokenasync(user); var callbackurl = url.page( "/account/confirmemail", pagehandler: null, values: new { userid = user.id, code = code }, protocol: request.scheme); await _emailsender.sendemailasync(input.email, "confirm your email", $"please confirm your account by <a href='{htmlencoder.default.encode(callbackurl)}'>clicking here</a>."); await _signinmanager.signinasync(user, ispersistent: false); return localredirect(returnurl); } foreach (var error in result.errors) { modelstate.addmodelerror(string.empty, error.description); } } // if we got this far, something failed, redisplay form return page(); } }
@page @model registermodel @{ viewdata["title"] = "register"; } <h1>@viewdata["title"]</h1> <div class="row"> <div class="col-md-4"> <form asp-route-returnurl="@model.returnurl" method="post"> <h4>create a new account.</h4> <hr /> <div asp-validation-summary="all" class="text-danger"></div>
<div class="form-group"> <label asp-for="input.name"></label> <input asp-for="input.name" class="form-control" /> <span asp-validation-for="input.name" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="input.dob"></label> <input asp-for="input.dob" class="form-control" /> <span asp-validation-for="input.dob" class="text-danger"></span> </div>
<div class="form-group"> <label asp-for="input.email"></label> <input asp-for="input.email" class="form-control" /> <span asp-validation-for="input.email" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="input.password"></label> <input asp-for="input.password" class="form-control" /> <span asp-validation-for="input.password" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="input.confirmpassword"></label> <input asp-for="input.confirmpassword" class="form-control" /> <span asp-validation-for="input.confirmpassword" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary">register</button> </form> </div> </div> @section scripts { <partial name="_validationscriptspartial" /> }
启动程序,运行注册页,保存成功后,查看数据库,如下所示:
1.6 其它相关页修改
下面这些最基本的页面,都需要把identityuser 改成webappidentitydemouser。
登录页 /identity/account/login
注册页 identity/account/register
会员管理后台主页 /identity/account/manage/index
个人资料页 /identity/account/manage/personaldata
个人资料删除 /identity/account/manage/deletepersonaldata
个人资料下载/identity/account/manage/ downloadpersonaldata.cshtml
分部页 _managenav.cshtml
下面是 account/manage/index.cshtml 页,已经加上自定义的二个用户字段信息,具体更新代码见官网
下面是/identity/account/manage/personaldata.cshtml 页,已经可以下载和删除用户数据
参考文献
上一篇: DataGridView操作小记(1)