IdentityServer4在Asp.Net Core中的应用(三)

    今天的内容是授权模式中的简化模式,还是先看以下授权流程图:

在这种模式中我们将与OpenID结合使用,所以首先我们要了解OpenID和OAuth的区别,关于他们的区别,在我上一篇博客《理解OpenID和OAuth的区别》中做了的一些简要的介绍,这里不再多说。

        授权服务器我们还是在之前的基础上改动,首先我们需要在Config类里面添加对OpenID Connect Identity Scopes的支持,与OAuth2.0相比,OIDC(OpenID Connect)同样需要Scopes的概念,他也需要保护Scopes范围的内容而也需要让用户去访问的内容,但是OIDC中这里的范围并不是用户要访问的API,而是用户标识、用户名、Email等信息。

        添加对OpenId(SubjectId) Profile(first name last name etc...)的支持范围,并返回一个IdentityReSource的集合,添加以下代码:

//添加对OpenID Profile范围的支持
 public static IEnumerable<IdentityResource> GetIdentityResources()
 {
       return new List<IdentityResource>{
              new IdentityResources.OpenId(),
              new IdentityResources.Profile(),
         };
 }

再天际一个客户端,基于Implicit授权模式,添加以下代码:

new Client(){
    ClientId="impClient",
    AllowedGrantTypes=GrantTypes.Implicit,

    //用于登录成功后的RedirectUri
    RedirectUris={"http://localhost:5004/signin-oidc"},

    //用于注销后的RedirectUri
    PostLogoutRedirectUris={"http://localhost:5004/signout-callback-oidc"},

    //允许访问的范围
    AllowedScopes={
             IdentityServerConstants.StandardScopes.OpenId,
             IdentityServerConstants.StandardScopes.Profile
           }
  }

下面我们还要将IdentityResource注入到IdentityServer中,在ConfigureService中,添加:

.AddInMemoryIdentityResources(Config.GetIdentityResources())

修改返回的TestUser的方法,在每一个用户中添加一个声明属性的集合,返回一个name和address信息,改动如下:

return new List<TestUser>{
     new TestUser(){
         SubjectId="1",
         Username="allen",
         Password="123456",
         Claims=new List<Claim>
              {
                  new Claim("name","Allen"),
                  new Claim("address","http://allen.com")
              }
         },
      new TestUser(){
         SubjectId="2",
         Username="alisa",
         Password="123456",
         Claims=new List<Claim>
                {
                    new Claim("name","Alisa"),
                    new Claim("address","http://alisa.com")
                }
         }

OIDC所需的所有协议已经内置在IdentityServer4中了,需要为登录、注销、同意授权内容以及错误等提供UI的部分,IdentityServer4提供了一个简单的基于MVC的UI界面,我们可以直接download到我们的服务端里,在控制台使用命令:

如果你是Windows系统,使用以下命令:

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))

如果你是MacOS或者Linux用户,使用:

\curl -L https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.sh | bash

执行完成后,会发现多了一个QuickStart文件夹,放置了所用到的Controller,Views文件夹下也放置了对应的视图,

由于我创建的是WebApi项目,所以还要在StartUp.cs里面将原来我们注释掉的app.UseMvc()解开,另外在配置默认路由前还要添加使用静态文件,以使用我们的静态文件夹下的样式,app.UseStaticFiles(); 以上内容都修改完成后,下面我们新建一个Mvc的项目,去请求我们的授权服务器,如何创建不再赘述,创建完成后添加对OIDC认证的支持,在ConfigureServices的方法中添加以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.IdentityModel.Tokens.Jwt;

namespace MvcClient
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

            //添加认证服务到DI中,
            services.AddAuthentication(options=>{
                //使用Cookies作为唯一的认证用户的主要手段
                options.DefaultScheme="Cookies";
                //需要用户登录才可进入该应用程序,使用OpenID Connect scheme
                options.DefaultChallengeScheme="oidc";
            })
            //添加可以处理Cookie的处理程序
            .AddCookie("Cookies")

            //配置OpenID Connect协议
            .AddOpenIdConnect("oidc",options=>{
                //OIDC协议执行完成,发布Cookie
                options.SignInScheme="Cookies";

                //授权服务器地址
                options.Authority="http://localhost:5000";
                options.RequireHttpsMetadata=false;
                //指定客户端Id
                options.ClientId="impClient";
                //保存令牌在Cookie中
                options.SaveTokens=true;
            });

            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (!env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            //添加认证中间件
            app.UseAuthentication();

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

注意配置启动时将MvcClient启动端口改为5004,因为我在服务端指定的客户端的端口为5004,接着我们添加一个Action,使他需要进行授权访问,

[Authorize]
public IActionResult Authorize()
{
      return View();
}

并添加对应的视图,展示用户信息:

@{
    ViewData["Title"] = "Authorize";
}

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

至此,我们的配置就完成了,下面我们运行看下效果,首先run下服务端,再启动我们的客户端,客户端点击Authorize菜单:

这个就对应我们那个需要QQ登录的界面了,需要通过认证,我们输入我们事先配置的用户名和密码,allen 123456,

到consent页面是要通过我们的授权,将我们用户信息共享给客户端,现在我们选择用户profile,点击允许:

当我们点击不允许读取用户信息的时候:

在不允许读取的情况下,我们是无法看到用户名的。下面我们再添加一个注销登录的方法,

//注销登录
public async Task LogOut()
{
     await HttpContext.SignOutAsync("Cookies");
     await HttpContext.SignOutAsync("oidc");
}

执行退出:

至此整个Implicit授权模式的过程就进行完了。

 

扫描二维码关注我的公众号,共同学习,共同进步!

posted @ 2018-03-30 15:00  Allen0910  阅读(422)  评论(0编辑  收藏  举报