乐时光博客园子

[reprinted:张子浩]

  OiDc可以说是OAuth的改造版,在最初的OAuth中,我们需要先请求一下认证服务器获取下Access_token,然后根据Access_token去Get资源服务器, 况且OAuth1 和 2 完全不兼容,易用性差,而OIDC可以在登陆的时候就把信息返回给你,不需要你在请求一下资源服务器。下面我们根据Oidc来做一个单点登录。

  新建三个项目(.NET Core Mvc)两个Client(端口5001,5002),一个Server(5000),首先在Server中添加IdentityServer4的引用。

  在Server中Config.cs用于模拟配置。

    public class Config    {        public static IEnumerable<ApiResource> GetApiResource()        {            return new List<ApiResource>            {                new ApiResource("api","My Api App")            };        }        public static IEnumerable<Client> GetClients()        {            return new List<Client>            {                new Client()                {                    ClientId = "mvc",                    AllowedGrantTypes = GrantTypes.Implicit,                    ClientSecrets ={                        new Secret("secret".Sha256())                    },                    RequireConsent = false,                    RedirectUris = {"http://localhost:5001/signin-oidc",                        "http://localhost:5002/signin-oidc" } ,                    PostLogoutRedirectUris = {"http://localhost:5001/signout-callback-oidc" ,                        "http://localhost:5002/signout-callback-oidc" },                    AllowedScopes = {                        IdentityServerConstants.StandardScopes.Profile,                        IdentityServerConstants.StandardScopes.OpenId                    }                }            };        }        public static List<TestUser> GetTestUsers()        {            return new List<TestUser>            {                new TestUser()                {                    SubjectId = "10000",                    Username = "zara",                    Password = "112233"                }            };        }        public static IEnumerable<IdentityResource> GetIdentityResources()        {            return new List<IdentityResource>            {                new IdentityResources.OpenId(),                new IdentityResources.Profile(),                new IdentityResources.Email()            };        }    }

GetClient方法中字段为RedirectUris是登陆成功返回的地址,并且我们采用隐式模式(因为只是传统web中传递Access_Token),RequireConsent是否出现同意授权页面,这个我们后续再细说.写完Config.cs后,我们需要依赖注入到IdentityServer中。

 <CookiePolicyOptions>(options =>                options.CheckConsentNeeded = context => =

 在Configure中添加代码 app.UseIdentityServer(); .我们还需要添加一个登陆页面,名为Account.cshtml.

@{    ViewData["Title"] = "Index";}<h2>Index</h2>@using mvcWebFirstSolucation.Models;@model LoginVM;<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 to log in .</h4>                <hr />                <div class="from-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="from-group">                    <label asp-for="PassWord"></label>                    <input asp-for="PassWord" type="password" class="form-control">                    <span asp-validation-for="UserName" class="text-danger"></span>                </div>                <div class="from-group">                    <button type="submit" class="btn btn-default">log in </button>                </div>            </form>        </section>    </div></div>@section Scripts{    @await Html.PartialAsync("_ValidationScriptsPartial")}

在控制器中我们写一个构造函数,用于将IdentityServer.Text给我们封装好的对象传过来,这个对象是我们在Config.cs中添加的用户信息,也就是GetClients的返回值,全都在 TestUserStore 中。其中还有一个提供好的方法,来给我们用,如果验证通过我们直接跳转到了传递过来的ReturnUrl.

    public class AccountController : Controller    {        private readonly TestUserStore _users;        public AccountController(TestUserStore ussotre)        {            _users = ussotre;        }        [HttpGet]        [Route("/Account/Login")]        public IActionResult Index(string ReturnUrl = null)        {            ViewData["returnUrl"] = ReturnUrl;            return View();        }        private IActionResult RediretToLocal(string returnUrl)        {            if (Url.IsLocalUrl(returnUrl))            {                return Redirect(returnUrl);            }            return RedirectToAction(nameof(HomeController.Index),"Home");        }        [HttpPost]        public async Task<IActionResult> Login(LoginVM vm,string returnUrl = null)        {            if (ModelState.IsValid)            {                ViewData["returnUrl"] = returnUrl;                var user =  _users.FindByUsername(vm.UserName);                if (user==null)                {                    ModelState.AddModelError(nameof(LoginVM.UserName), "userName is exists");                }                else                {                    if(_users.ValidateCredentials(vm.UserName, vm.PassWord))                    {                        var props = new AuthenticationProperties                        {                            IsPersistent = true,                            ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30))                        };                        await Microsoft.AspNetCore.Http                            .AuthenticationManagerExtensions                                .SignInAsync( HttpContext, user.SubjectId, user.Username, props );                        return RediretToLocal(returnUrl);                    }                    ModelState.AddModelError(nameof(LoginVM.PassWord), "Wrong Password");                }            }            return View();        }    }

这个时候最基本的服务端已经配置成功了,我们开始配置受保护的客户端吧。

在客户端中我们不需要引入IdentityServer,因为我们只是去请求服务端然后看看cookies有没有在而已,所以我们只需要给受保护的客户端的Api做好安全判断就好.

在受保护的控制器中添加 [Authorize] 标识。然后再Startup.cs中添加安全验证。并且在Configure中use下 app.UseAuthentication(); 

public void ConfigureServices(IServiceCollection services)        {            services.AddAuthentication(options =>            {                options.DefaultScheme = "Cookies";                options.DefaultChallengeScheme = "oidc";            }).AddCookie("Cookies").AddOpenIdConnect("oidc", options => {                options.SignInScheme = "Cookies";                options.Authority = "http://localhost:5000";                options.RequireHttpsMetadata = false;                options.ClientId = "mvc";                options.ClientSecret = "secret";                options.SaveTokens = true;            });            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);        }

在首页中最好遍历下Claims对象,这个是通过OIDC直接给我们返回回来的.(最后另一个客户端也这么干!)

<div>    @foreach (var claim in User.Claims)    {        <dl>            <dt>@claim.Type</dt>            <dd>@claim.Value</dd>        </dl>    }</div>

现在我们启动项目看一下效果吧。

 .NET Core IdentityServer4实战 第Ⅴ章-单点登录

 

本文来源于互联网:.NET Core IdentityServer4实战 第Ⅴ章-单点登录  https://www.lesg.cn  本文中来自互联网如有侵权请联系删除。

上下篇:

相关推荐