2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 【ASP.NET Core分布式项目实战】(三)整理IdentityServer4 MVC授权 Consent功能实现...

【ASP.NET Core分布式项目实战】(三)整理IdentityServer4 MVC授权 Consent功能实现...

时间:2018-10-02 05:55:46

相关推荐

【ASP.NET Core分布式项目实战】(三)整理IdentityServer4 MVC授权 Consent功能实现...

【 Core分布式项目实战】(三)整理IdentityServer4 MVC授权、Consent功能实现 原文:【 Core分布式项目实战】(三)整理IdentityServer4 MVC授权、Consent功能实现

本博客根据/my/course/5视频整理(内容可能会有部分,推荐看源视频学习)

前言

由于之前的博客都是基于其他的博客进行开发,现在重新整理一下方便以后后期使用与学习

新建IdentityServer4服务端

服务端也就是提供服务,如QQ Weibo等。

新建项目解决方案AuthSample.

新建一个 Core Web Application 项目MvcCookieAuthSample,选择模板Web 应用程序 不进行身份验证。

给网站设置默认地址 http://localhost:5000

第一步:添加Nuget包:IdentityServer4

添加IdentityServer4 引用:

Install-Package IdentityServer4

第二步:添加Config.cs配置类

然后添加配置类Config.cs:

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using IdentityServer4;using IdentityServer4.Models;using IdentityServer4.Test;namespace MvcCookieAuthSample{public class Config{//所有可以访问的Resourcepublic 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={//运行访问的资源 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>{//这里实际是claims的返回资源new IdentityResources.OpenId(),new IdentityResources.Profile(),new IdentityResources.Email()};}}}

View Code

第三步:添加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){...app.UseIdentityServer();...}

注册登录实现

我们还需要新建一个ViewModels,在ViewModels中新建RegisterViewModel.cs和LoginViewModel.cs来接收表单提交的值以及来进行强类型视图

using ponentModel.DataAnnotations;namespace MvcCookieAuthSample.ViewModels{public class RegisterViewModel{[Required]//必须的[DataType(DataType.EmailAddress)]//内容检查是否为邮箱public string Email { get; set; }[Required]//必须的[DataType(DataType.Password)]//内容检查是否为密码public string Password { get; set; }[Required]//必须的[DataType(DataType.Password)]//内容检查是否为密码public string ConfirmedPassword { get; set; }}}

View Code

using System;using System.Collections.Generic;using ponentModel.DataAnnotations;using System.Linq;using System.Threading.Tasks;namespace MvcCookieAuthSample.ViewModels{public class LoginViewModel{[Required]public string UserName { get; set; }[Required]//必须的[DataType(DataType.Password)]//内容检查是否为密码public string Password { get; set; }}}

View Code

在Controllers文件夹下新建AdminController.cs

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Mvc;namespace MvcCookieAuthSample.Controllers{public class AdminController : Controller{public IActionResult Index(){return View();}}}

View Code

在Views文件夹下新建Admin文件夹,并在Admin文件夹下新建Index.cshtml

@{ViewData["Title"] = "Admin";}<h2>@ViewData["Title"]</h2><p>Admin Page</p>

View Code

在Controllers文件夹下新建AccountController.cs

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Mvc;using IdentityServer4.Test;using Microsoft.AspNetCore.Identity;using MvcCookieAuthSample.ViewModels;using Microsoft.AspNetCore.Authentication;namespace MvcCookieAuthSample.Controllers{public class AccountController : Controller{private readonly TestUserStore _users;public AccountController(TestUserStore users){_users = users;}//内部跳转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到modelModelState.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){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 = _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))};await Microsoft.AspNetCore.Http.AuthenticationManagerExtensions.SignInAsync(HttpContext, user.SubjectId, user.Username, prop);}}return RedirectToLocal(returnUrl);}return View();}public async Task<IActionResult> Logout(){await HttpContext.SignOutAsync();return RedirectToAction("Index", "Home");}}}

View Code

然后在Views文件夹下新增Account文件夹并新增Register.cshtml与Login.cshtml视图

@{ViewData["Title"] = "Register";}@using MvcCookieAuthSample.ViewModels;@model RegisterViewModel;<h2>@ViewData["Title"]</h2><h3>@ViewData["Message"]</h3><div class="row"><div class="col-md-4">@* 这里将asp-route-returnUrl="@ViewData["returnUrl"],就可以在进行register的post请求的时候接收到returnUrl *@<form method="post" asp-route-returnUrl="@ViewData["returnUrl"]"><h4>Create a new account.</h4><hr />@*统一显示错误信息*@<div class="text-danger" asp-validation-summary="All"></div><div class="form-group"><label asp-for="Email"></label><input asp-for="Email" class="form-control" /><span asp-validation-for="Email" class="text-danger"></span></div><div class="form-group"><label asp-for="Password"></label><input asp-for="Password" class="form-control" /><span asp-validation-for="Password" class="text-danger"></span></div><div class="form-group"><label asp-for="ConfirmedPassword"></label><input asp-for="ConfirmedPassword" class="form-control" /><span asp-validation-for="ConfirmedPassword" class="text-danger"></span></div><button type="submit" class="btn btn-default">Register</button></form></div></div>

View Code

@{ViewData["Title"] = "Login";}@using MvcCookieAuthSample.ViewModels;@model LoginViewModel;<div class="row"><div class="col-md-4"><section><form method="post" asp-controller="Account" asp-action="Login" asp-route-returnUrl="@ViewData["returnUrl"]"><h4>Use a local account to log in.</h4><hr />@*统一显示错误信息*@<div class="text-danger" asp-validation-summary="All"></div><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-default">Log in</button></div></form></section></div></div>@section Scripts{@await Html.PartialAsync("_ValidationScriptsPartial")}

View Code

我们接下来要修改_Layout.cshtml视图页面判断注册/登陆按钮是否应该隐藏

完整的_Layout.cshtml代码:

<!DOCTYPE html><html><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>@ViewData["Title"] - MvcCookieAuthSample</title><environment include="Development"><link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /><link rel="stylesheet" href="~/css/site.css" /></environment><environment exclude="Development"><link rel="stylesheet" href="/ajax/bootstrap/3.3.7/css/bootstrap.min.css"asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /><link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /></environment></head><body><nav class="navbar navbar-inverse navbar-fixed-top"><div class="container"><div class="navbar-header"><button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">MvcCookieAuthSample</a></div><div class="navbar-collapse collapse"><ul class="nav navbar-nav"><li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li><li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li><li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li></ul>@if (User.Identity.IsAuthenticated){<form asp-action="Logout" asp-controller="Account" method="post"><ul class="nav navbar-nav navbar-right"><li><a title="Welcome" asp-controller="Admin" asp-action="Index">@User.Identity.Name</a></li><li><button type="submit" class="btn btn-link navbar-btn navbar-link">Log out</button></li></ul></form>}else{<ul class="nav navbar-nav navbar-right"><li><a asp-area="" asp-controller="Account" asp-action="Register">Register</a></li><li><a asp-area="" asp-controller="Account" asp-action="Login">Log in</a></li></ul>}</div></div></nav><div class="container body-content">@RenderBody()<hr /><footer><p>&copy; - MvcCookieAuthSample</p></footer></div><environment include="Development"><script src="~/lib/jquery/dist/jquery.js"></script><script src="~/lib/bootstrap/dist/js/bootstrap.js"></script><script src="~/js/site.js" asp-append-version="true"></script></environment><environment exclude="Development"><script src="/ajax/jquery/jquery-2.2.0.min.js"asp-fallback-src="~/lib/jquery/dist/jquery.min.js"asp-fallback-test="window.jQuery"crossorigin="anonymous"integrity="sha384-K+ctZQ+LL8q6tP7I94W+qzQsfRV2a+AfHIi9k8z8l9ggpc8X+Ytst4yBo/hH+8Fk"></script><script src="/ajax/bootstrap/3.3.7/bootstrap.min.js"asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"crossorigin="anonymous"integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"></script><script src="~/js/site.min.js" asp-append-version="true"></script></environment>@RenderSection("Scripts", required: false)</body></html>

View Code

最后给AdminController加上 [Authorize] 特性标签即可

然后我们就可以运行网站,输入用户名和密码进行登录了

新建客户端

新建一个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=> {//配置oidcoptions.SignInScheme = "Cookies";options.Authority = "http://localhost:5000";options.RequireHttpsMetadata = false;options.ClientId = "mvc";options.ClientSecret = "secret";options.SaveTokens = true;});

在管道中使用Authentication

app.UseAuthentication();

接下来我们在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>

View Code

这边的内容是根据我们在IdentityServer服务中定义的返回资源决定的

Consent功能实现

首先在ViewModels文件夹下创建两个视图模型

ScopeViewModel.cs

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;namespace MvcCookieAuthSample.ViewModels{//领域public class ScopeViewModel{public string Name { get; set; }public string DisplayName { get; set; }public string Description { get; set; }public bool Emphasize { get; set; }public bool Required { get; set; }public bool Checked { get; set; }}}

View Code

ConsentViewModel.cs

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;namespace MvcCookieAuthSample.ViewModels{public class ConsentViewModel{public string ClientId { get; set; }public string ClientName { get; set; }public string ClientUrl { get; set; }public string ClientLogoUrl { get; set; }public bool AllowRememberConsent { get; set; }public IEnumerable<ScopeViewModel> IdentityScopes { get; set; }public IEnumerable<ScopeViewModel> ResourceScopes { get; set; }}}

View Code

我们在MvcCookieAuthSample项目中添加新控制器ConsentController

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using Microsoft.AspNetCore.Mvc;using MvcCookieAuthSample.ViewModels;using IdentityServer4.Models;using IdentityServer4.Services;using IdentityServer4.Stores;namespace MvcCookieAuthSample.Controllers{public class ConsentController : Controller{private readonly IClientStore _clientStore;private readonly IResourceStore _resourceStore;private readonly IIdentityServerInteractionService _identityServerInteractionService;public ConsentController(IClientStore clientStore, IResourceStore resourceStore, IIdentityServerInteractionService identityServerInteractionService){_clientStore = clientStore;_resourceStore = resourceStore;_identityServerInteractionService = identityServerInteractionService;}private async Task<ConsentViewModel> BuildConsentViewModel(string returnUrl){var request =await _identityServerInteractionService.GetAuthorizationContextAsync(returnUrl);if (request == null)return null;var client =await _clientStore.FindEnabledClientByIdAsync(request.ClientId);var resources =await _resourceStore.FindEnabledResourcesByScopeAsync(request.ScopesRequested);return CreateConsentViewModel(request, client, resources);}private ConsentViewModel CreateConsentViewModel(AuthorizationRequest request,Client client,Resources resources){var vm = new ConsentViewModel();vm.ClientName = client.ClientName;vm.ClientLogoUrl = client.LogoUri;vm.ClientUrl = client.ClientUri;vm.AllowRememberConsent = client.AllowRememberConsent;vm.IdentityScopes = resources.IdentityResources.Select(i => CreateScopeViewModel(i));vm.ResourceScopes = resources.ApiResources.SelectMany(i =>i.Scopes).Select(i=>CreateScopeViewModel(i));return vm;}private ScopeViewModel CreateScopeViewModel(IdentityResource identityResource){return new ScopeViewModel{Name = identityResource.Name,DisplayName = identityResource.DisplayName,Description = identityResource.Description,Required = identityResource.Required,Checked = identityResource.Required,Emphasize = identityResource.Emphasize};}private ScopeViewModel CreateScopeViewModel(Scope scope){return new ScopeViewModel{Name = scope.Name,DisplayName = scope.DisplayName,Description = scope.Description,Required = scope.Required,Checked = scope.Required,Emphasize = scope.Emphasize};}[HttpGet]public async Task<IActionResult> Index(string returnUrl){var model =await BuildConsentViewModel(returnUrl);if (model==null){}return View(model);}}}

View Code

然后新建Idenx.cshtml视图和_ScopeListitem.cshtml分部视图

_ScopeListitem.cshtml

@using MvcCookieAuthSample.ViewModels;@model ScopeViewModel<li><label><input type="checkbox" name="ScopesConsented" id="scopes_@Model.Name" value="@Model.Name" checked="@Model.Checked" disabled="@Model.Required"/><strong>@Model.Name</strong>@if (Model.Emphasize){<span class="glyphicon glyphicon-exclamation-sign"></span>}</label>@if (string.IsNullOrWhiteSpace(Model.Description)){<div><label for="scopes_@Model.Name">@Model.Description</label></div>}</li>

View Code

Idenx.cshtml

@using MvcCookieAuthSample.ViewModels;@model ConsentViewModel<p>Consent Page</p><!--Client Info--><div class="row page-header"><div class="col-sm-10">@if (!string.IsNullOrWhiteSpace(Model.ClientLogoUrl)){<div><img src="@Model.ClientLogoUrl" /></div>}<h1>@Model.ClientName<small>希望使用你的账户</small></h1></div></div><!--Scope Info--><div class="row"><div class="col-sm-8"><form asp-action="Index">@if (Model.IdentityScopes.Any()){<div><div class="panel-heading"><span class="glyphicon glyphicon-user"></span>用户信息</div><ul class="list-group">@foreach (var scope in Model.IdentityScopes){@Html.Partial("_ScopeListitem",scope)}</ul></div>}@if (Model.ResourceScopes.Any()){<div><div class="panel-heading"><span class="glyphicon glyphicon-tasks"></span>应用权限</div><ul class="list-group">@foreach (var scope in Model.ResourceScopes){@Html.Partial("_ScopeListitem",scope)}</ul></div>}</form></div></div>

View Code

最后我们修改Config.cs,增加一些信息

using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;using IdentityServer4;using IdentityServer4.Models;using IdentityServer4.Test;namespace MvcCookieAuthSample{public class Config{//所有可以访问的Resourcepublic 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={//运行访问的资源 IdentityServerConstants.StandardScopes.Profile,IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Email,},RedirectUris={"http://localhost:5001/signin-oidc"},//跳转登录到的客户端的地址PostLogoutRedirectUris={"http://localhost:5001/signout-callback-oidc"},//跳转登出到的客户端的地址RequireConsent=true,//是否需要用户点击确认进行跳转,改为点击确认后进行跳转ClientName="MVC Clent",ClientUri="http://localhost:5001",LogoUri="/content/packageimages/aspnetcore-runtimepackagestore.2.0.0.png",AllowRememberConsent=true,}};}//测试用户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>{//这里实际是claims的返回资源new IdentityResources.OpenId(),new IdentityResources.Profile(),new IdentityResources.Email()};}}}

我们这个时候访问首页http://localhost:5001会自动跳转到ocalhost:5000/account/login登录

登录之后会自动跳转到登录确认页面

posted on -03-29 00:27 NET未来之路 阅读(...) 评论(...) 编辑 收藏

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