資料
我們基於之前的MvcCookieAuthSample來做開發
MvcCookieAuthSample下載地址:https://files.cnblogs.com/files/wyt007/ASPNETCore%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8.rar
MvcCookieAuthSample教程地址:http://www.cnblogs.com/wyt007/p/8204731.html
正文
給網站設置默認地址 http://localhost:5000
首先,我們將之前寫的系統的Identity注釋掉,在Startup.cs中
第一步:添加Nuget包:IdentityServer4
我們可以在vscode中使用ctrl+P鍵來打開命令面板。然后輸入nuget按回車,輸入identityserver4后按回車來選擇版本進行安裝
第二步:添加Config.cs配置類
我們接下來添加一個Config.cs類,這個類是用來初始化IdentityServer的
using System.Collections; using System.Collections.Generic; using IdentityServer4; using IdentityServer4.Models; using IdentityServer4.Test; namespace MvcCookieAuthSample { public class Config { //所有可以訪問的Resource public static IEnumerable<ApiResource> GetApiResources() { return new List<ApiResource> { new ApiResource("api1","API Application") }; } //客戶端 public static IEnumerable<Client> GetClients() { return new List<Client> { new Client() { ClientId="mvc", AllowedGrantTypes= GrantTypes.Implicit,//模式:最簡單的模式 ClientSecrets={//私鑰 new Secret("secret".Sha256()) }, AllowedScopes={//可以訪問的Resource IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.OpenId, }, RedirectUris={"http://localhost:5001/signin-oidc"},//跳轉登錄到的客戶端的地址 PostLogoutRedirectUris={"http://localhost:5001/signout-callback-oidc"},//跳轉登出到的客戶端的地址 RequireConsent=false//是否需要用戶點擊確認進行跳轉 } }; } //測試用戶 public static List<TestUser> GetTestUsers() { return new List<TestUser>{ new TestUser{ SubjectId="10000", Username="wyt", Password="password" } }; } //定義系統中的資源 public static IEnumerable<IdentityResource> GetIdentityResources() { return new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Email() }; } } }
以上使用IdentityServer4測試數據類添加數據,直接存在內存中。IdentityServer4 是支持持久化。
第三步:添加Startup配置
引用命名空間:
using IdentityServer4;
然后打開Startup.cs 加入如下:
services.AddIdentityServer() .AddDeveloperSigningCredential()//添加開發人員簽名憑據 .AddInMemoryApiResources(Config.GetApiResources())//添加內存apiresource .AddInMemoryClients(Config.GetClients())//添加內存client .AddInMemoryIdentityResources(Config.GetIdentityResources())//添加系統中的資源 .AddTestUsers(Config.GetTestUsers());//添加測試用戶
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { ... //app.UseAuthentication(); app.UseIdentityServer(); ...
接着安裝UI,UI部分也可以自己編寫,也就是登錄 注銷 允許和錯誤。
可以到 https://github.com/IdentityServer/IdentityServer4.Quickstart.UI/tree/release 下載,然后解壓到項目目錄下。
也可以使用命令提示符快速安裝:
powershell iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))
在項目目錄下打開命令提示符,輸入以上命令。
更多信息,可以查看官方readme:https://github.com/IdentityServer/IdentityServer4.Quickstart.UI/blob/release/README.md
大神博客:https://www.cnblogs.com/linezero/p/identityserver4openidconnect.html
修改LoginViewModel,將Email改為UserName,並修改強類型視圖的引用部分Login.cshtml
namespace MvcCookieAuthSample.ViewModels { public class LoginViewModel { //[Required]//必須的 //[DataType(DataType.EmailAddress)]//內容檢查是否為郵箱 //public string Email { get; set; } [Required] public string UserName { get; set; } [Required]//必須的 [DataType(DataType.Password)]//內容檢查是否為密碼 public string Password { get; set; } } }
修改AccountController,原來的_userManager和_signInManager不再使用
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authentication.Cookies; using System.Security.Claims; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using Microsoft.AspNetCore.Identity; using MvcCookieAuthSample.Models; using System.Threading.Tasks; using MvcCookieAuthSample.ViewModels; using IdentityServer4.Test; using System; namespace MvcCookieAuthSample.Controllers { public class AccountController : Controller { // private UserManager<ApplicationUser> _userManager;//創建用戶的 // private SignInManager<ApplicationUser> _signInManager;//用來登錄的 private readonly TestUserStore _users; public AccountController(TestUserStore users) { _users=users; } // //依賴注入 // public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager) // { // _userManager = userManager; // _signInManager = signInManager; // } //內部跳轉 private IActionResult RedirectToLocal(string returnUrl) { if (Url.IsLocalUrl(returnUrl)) {//如果是本地 return Redirect(returnUrl); } return RedirectToAction(nameof(HomeController.Index), "Home"); } //添加驗證錯誤 private void AddError(IdentityResult result) { //遍歷所有的驗證錯誤 foreach (var error in result.Errors) { //返回error到model ModelState.AddModelError(string.Empty, error.Description); } } public IActionResult Register(string returnUrl = null) { ViewData["returnUrl"] = returnUrl; return View(); } [HttpPost] public async Task<IActionResult> Register(RegisterViewModel registerViewModel, string returnUrl = null) { // if (ModelState.IsValid) // { // ViewData["returnUrl"] = returnUrl; // var identityUser = new ApplicationUser // { // Email = registerViewModel.Email, // UserName = registerViewModel.Email, // NormalizedUserName = registerViewModel.Email // }; // var identityResult = await _userManager.CreateAsync(identityUser, registerViewModel.Password); // if (identityResult.Succeeded) // { // //注冊完成登錄生成cookies信息 // await _signInManager.SignInAsync(identityUser, new AuthenticationProperties { IsPersistent = true }); // return RedirectToLocal(returnUrl); // } // else//注冊失敗 // { // //添加驗證錯誤 // AddError(identityResult); // } // } return View(); } public IActionResult Login(string returnUrl = null) { ViewData["returnUrl"] = returnUrl; return View(); } [HttpPost] public async Task<IActionResult> Login(LoginViewModel loginViewModel, string returnUrl = null) { if (ModelState.IsValid) { ViewData["returnUrl"] = returnUrl; //var user = await _userManager.FindByEmailAsync(loginViewModel.Email); var user = _users.FindByUsername(loginViewModel.UserName); if (user == null) { ModelState.AddModelError(nameof(loginViewModel.UserName), "UserName not exists"); } else { if (_users.ValidateCredentials(loginViewModel.UserName,loginViewModel.Password)) { //是否記住 var prop = new AuthenticationProperties() { IsPersistent = true, ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30)) }; //HttpContext.SignInAsync(user.SubjectId, user.Username, prop); await Microsoft.AspNetCore.Http.AuthenticationManagerExtensions.SignInAsync(HttpContext, user.SubjectId, user.Username, prop); } } //賬號密碼先不做驗證,需要可以自己寫 //await _signInManager.SignInAsync(user, new AuthenticationProperties { IsPersistent = true }); return RedirectToLocal(returnUrl); } return View(); } //登出 public async Task<IActionResult> Logout() { await HttpContext.SignOutAsync(); return RedirectToAction("Index", "Home"); } } }
接下來我們需要將原來的Program.cs中的數據庫初始化的內容注釋掉
然后我們就可以運行網站,輸入用戶名和密碼進行登錄了
新建客戶端
新建一個MVC網站MvcClient
dotnet new mvc --name MvcClient
給網站設置默認地址 http://localhost:5001
MVC的網站已經內置幫我們實現了Identity,所以我們不需要再額外添加Identity引用
添加認證
services.AddAuthentication(options => { options.DefaultScheme = "Cookies";//使用Cookies認證 options.DefaultChallengeScheme = "oidc";//使用oidc }) .AddCookie("Cookies")//配置Cookies認證 .AddOpenIdConnect("oidc",options=> {//配置oidc options.SignInScheme = "Cookies"; options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.ClientId = "mvc"; options.ClientSecret = "secret"; options.SaveTokens = true; });
在管道中使用Authentication
app.UseAuthentication();
Login.cshtml 頁面接收returnUrl進行跳轉

<form method="post" asp-controller="Account" asp-action="Login"> <h4>Use a local account to log in.</h4> <hr /> @*用於登錄后進行跳轉*@ <input type="hidden" name="returnUrl" value="@ViewData["returnUrl"]" /> <div class="form-group"> <label asp-for="UserName"></label> <input asp-for="UserName" class="form-control" /> <span asp-validation-for="UserName" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="Password"></label> <input asp-for="Password" type="password" class="form-control" /> <span asp-validation-for="Password" class="text-danger"></span> </div> <div class="form-group"> <button type="submit" class="btn btn-block btn-danger">Log in</button> </div> </form>
接下來我們在HomeController上打上 [Authorize] 標簽,然后啟動運行
我們這個時候訪問首頁http://localhost:5001會自動跳轉到ocalhost:5000/account/login登錄
登錄之后會自動跳轉回來
我們可以在Home/About頁面將claim的信息顯示出來
@{ ViewData["Title"] = "About"; } <h2>@ViewData["Title"]</h2> <h3>@ViewData["Message"]</h3> <dl> @foreach (var claim in User.Claims) { <dt>@claim.Type</dt> <dt>@claim.Value</dt> } </dl>
這邊的內容是根據我們在IdentityServer服務中定義的返回資源決定的