前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Asp.Net Core 中IdentityServer4 授权流程及刷新Token

Asp.Net Core 中IdentityServer4 授权流程及刷新Token

作者头像
Jlion
发布2022-04-07 14:15:50
1.9K0
发布2022-04-07 14:15:50
举报
文章被收录于专栏:.Net Core 技术栈.Net Core 技术栈

一、前言

上面分享了IdentityServer4 两篇系列文章,核心主题主要是密码授权模式自定义授权模式,但是仅仅是分享了这两种模式的使用,这篇文章进一步来分享IdentityServer4的授权流程及refreshtoken

系列文章目录(没看过的先看这几篇文章再来阅读本文章):

  • Asp.Net Core IdentityServer4 中的基本概念
  • Asp.Net Core 中IdentityServer4 授权中心之应用实战
  • Asp.Net Core 中IdentityServer4 授权中心之自定义授权模式

为了继续保持IdentityServer4 系列博客分享上下文一致,我这里再把上回授权中心拆分后的图贴出来,如图:

图中的授权中心就是通过IdentityServer4实现的授权服务中心,我下面就直接用授权中心代替IdentityServer4的授权服务来继续述说,也感谢大家对我的支持,一直阅读我的文章。

二、授权流程

2.1 客户端验证流程图

流程图中,客户端仅仅会到授权中心 请求一次,并拿到验证公钥返回给Api资源拥有端,后面客户端再次尝试请求Api资源时候就不会再到授权中心去获取验证公钥,会直接用之前获取到的公钥进行验证,验证通过则授权通过。

2.2 授权及刷新refresh_token 流程图

然而通过授权中心 获取到的access_token 是有有效时间的,如果失效则需要通过refresh_token 重新到授权中心去刷新获取最新的access_token,整体的流程图如下:

客户端携带上一次获取到的access_token 请求受保护的Api资源时,通过公钥进行验证时发现access_token已经过期,则客户端再携带refresh_token授权中心再次发起请求,刷新access_token以获得最新的access_tokenrefresh_token,用最新的access_token 去获取受保护的Api资源,这样可以减少客户端多次跳转登录授权页面,提高用户体验。

三、应用实战

说到例子,我这里不从零开始撸代码, 还是在之前的代码基础上继续改造代码,在原有的定义客户端的代码中新增刷新access_token的相关配置,代码如下:

代码语言:javascript
复制
public static IEnumerable<Client> GetClients()
{
     return new List<Client>
     {
         new Client()
         {
             ClientId =OAuthConfig.UserApi.ClientId,
             AllowedGrantTypes = new List<string>()
             {
                 GrantTypes.ResourceOwnerPassword.FirstOrDefault(),//Resource Owner Password模式
                 GrantTypeConstants.ResourceWeixinOpen,
             },
             ClientSecrets = {new Secret(OAuthConfig.UserApi.Secret.Sha256()) },
             AllowOfflineAccess = true,//如果要获取refresh_tokens ,必须把AllowOfflineAccess设置为true
             AllowedScopes= {
                 OAuthConfig.UserApi.ApiName,
                 StandardScopes.OfflineAccess,
             },
             AccessTokenLifetime = OAuthConfig.ExpireIn,
         },

      };
 }

如果你需要刷新access_token,则需要把AllowOfflineAccess设置true,同时添加StandardScopes.OfflineAccess 这个Scopes,主要代码如下:

代码语言:javascript
复制
AllowOfflineAccess = true,//如果要获取refresh_tokens ,必须把AllowOfflineAccess设置为true
AllowedScopes= {
     OAuthConfig.UserApi.ApiName,
     StandardScopes.OfflineAccess,//如果要获取refresh_tokens ,必须在scopes中加上OfflineAccess
},

授权中心,完整代码如下:

OAuthMemoryData 代码如下:

代码语言:javascript
复制
/// <summary>
///
/// </summary>
public class OAuthMemoryData
{
    /// <summary>
    /// 资源
    /// </summary>
    /// <returns></returns>
    public static IEnumerable<ApiResource> GetApiResources()
    {
        return new List<ApiResource>
        {
            new ApiResource(OAuthConfig.UserApi.ApiName,OAuthConfig.UserApi.ApiName),
        };
    }

    public static IEnumerable<Client> GetClients()
    {
        return new List<Client>
        {
            new Client()
            {
                ClientId =OAuthConfig.UserApi.ClientId,
                AllowedGrantTypes = new List<string>()
                {
                    GrantTypes.ResourceOwnerPassword.FirstOrDefault(),//Resource Owner Password模式
                    GrantTypeConstants.ResourceWeixinOpen,
                },
                ClientSecrets = {new Secret(OAuthConfig.UserApi.Secret.Sha256()) },
                AllowOfflineAccess = true,//如果要获取refresh_tokens ,必须把AllowOfflineAccess设置为true
                AllowedScopes= {
                    OAuthConfig.UserApi.ApiName,
                    StandardScopes.OfflineAccess,
                },
                AccessTokenLifetime = OAuthConfig.ExpireIn,
            },

        };
    }

    /// <summary>
    /// 测试的账号和密码
    /// </summary>
    /// <returns></returns>
    public static List<TestUser> GetTestUsers()
    {
        return new List<TestUser>
        {
            new TestUser()
            {
                 SubjectId = "1",
                 Username = "test",
                 Password = "123456"
            },
        };
    }

    /// <summary>
    /// 微信openId 的测试用户
    /// </summary>
    /// <returns></returns>
    public static List<TestUser> GetWeiXinOpenIdTestUsers()
    {
        return new List<TestUser>
        {
            new TestUser(){
              SubjectId="owerhwroogs3902openId",
            }
         };
    }
}

Startup 完整代码如下:

代码语言:javascript
复制
 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)
    {
        services.AddControllers();

        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        #region 内存方式
        //services.AddIdentityServer()
        //    .AddDeveloperSigningCredential()
        //    .AddInMemoryApiResources(OAuthMemoryData.GetApiResources())
        //    .AddInMemoryClients(OAuthMemoryData.GetClients())
        //    .AddTestUsers(OAuthMemoryData.GetTestUsers());
        #endregion

        #region 数据库存储方式
        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryApiResources(OAuthMemoryData.GetApiResources())
            //.AddInMemoryClients(OAuthMemoryData.GetClients())
            .AddClientStore<ClientStore>()
            .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
            .AddExtensionGrantValidator<WeiXinOpenGrantValidator>();//添加微信端自定义方式的验证
        #endregion
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
           app.UseDeveloperExceptionPage();
        }

        app.UseIdentityServer();

        app.UseRouting();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

授权中心代码基本上已经改造完成,我们用postman 访问授权中心 试一试,如下图:

访问结果中已经包含了refresh_tokenaccess_token等相关信息。

我们再来通过access_token 访问Api资源(上两篇有相关代码,未阅读上两篇先去查阅)这里我就直接携带access_token去访问,如图:

访问成功!!

我们再来刷新下refresh_token ,访问如图:

刷新refresh_token成功。我们到这里再来做一个小小的测试,测试上面的授权流程中的,第4,5 步,上面说到第4步主要是客户端第一次请求Api资源时会向ids4服务网关去请求获取验证公钥, 获取成功返回给Api资源并存储在内存中,后续不再会到ids4服务去获取验证公钥

我们把上面的授权中心 (ids4服务网关)停止运行,再来用之前的access_token请求Api资源,如下图:

现在已经确定授权中心(ids4服务网关)确实停止了,不能访问了,那我们再来通过之前未过期的access_token来请求Api资源网关,结果如下图:

完美,请求还是成功,这完全证明:客户端请求Api资源网关(受保护的资源)时,第一次收到请求会到授权中心(ids4服务网关)获取验证公钥,并保持到内存中,后面的请求不会再到授权中心去获得验证公钥,而是Api资源网关(受保护的资源)中直接通过保存下来的验证公钥进行验证,从而通过授权

·end·

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 dotNET博士 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 二、授权流程
    • 2.1 客户端验证流程图
      • 2.2 授权及刷新refresh_token 流程图
      • 三、应用实战
      相关产品与服务
      云数据库 Redis
      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档