Identity server 4 authorization principle and application of refresh Token in Asp.Net Core

Keywords: Lambda Database

I. Preface

The above two series of articles on identity server 4 are shared. The core topics are mainly password authorization mode and user-defined authorization mode, but only the use of these two modes is shared. This article will further share the authorization process and refreshtoken of identity server 4.

List of articles in the series (if you haven't read it, please read these articles before reading this article):

In order to keep the identity server 4 series blog sharing context consistent, I will post the split map of the last authorization center, as shown in the figure:

The authorization center in the figure is the Authorization Service Center implemented through IdentityServer4. I will use the authorization center to replace the authorization service of IdentityServer4. Thank you for your support, and read my article all the time.

2, Authorization process

2.1 client verification flow chart

In the flowchart, the client only requests the authorization center once, and gets the verification public key and returns it to the Api resource owner. When the client tries to request the Api resource again, it will not go to the authorization center to obtain the verification public key, and will directly use the previously obtained public key for verification. If the verification is passed, the authorization is passed.

2.2 authorization and refresh "refresh token" flowchart

However, the access token obtained through the authorization center has a valid time. If it fails, you need to refresh and obtain the latest access token through the refresh token. The overall flow chart is as follows:

When the client carries the access token obtained last time to request the protected Api resources, it is found that the access token has expired when it is verified through the public key. Then the client carries the refresh token to the authorization center to make a request again, refresh the access token to obtain the latest access token and refresh token, and use the latest access token To obtain the protected Api resources, it can reduce the number of times clients jump to the login authorization page, and improve the user experience.

3, Practical application

When it comes to examples, I will not roll up the code from scratch, or continue to transform the code based on the previous code. In the original code defining the client, I will add and refresh the relevant configuration of access token. The code is as follows:

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 mode
                 GrantTypeConstants.ResourceWeixinOpen,
             },
             ClientSecrets = {new Secret(OAuthConfig.UserApi.Secret.Sha256()) },
             AllowOfflineAccess = true,//If you want to get refresh_tokens, AllowOfflineAccess must be set to true
             AllowedScopes= {
                 OAuthConfig.UserApi.ApiName,
                 StandardScopes.OfflineAccess,
             },
             AccessTokenLifetime = OAuthConfig.ExpireIn,
         },

      };
 }

If you need to refresh access_token, you need to set AllowOfflineAccess to true and add StandardScopes.OfflineAccess. The main code is as follows:

AllowOfflineAccess = true,//If you want to get refresh_tokens, AllowOfflineAccess must be set to true
AllowedScopes= {
     OAuthConfig.UserApi.ApiName,
     StandardScopes.OfflineAccess,//If you want to get refresh_tokens, you must add OfflineAccess to the scopes
},

Authorization center, complete code as follows:

OAuthMemoryData code is as follows:

/// <summary>
/// 
/// </summary>
public class OAuthMemoryData
{
        /// <summary>
        //Resources
        /// </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 mode
                        GrantTypeConstants.ResourceWeixinOpen,
                    },
                    ClientSecrets = {new Secret(OAuthConfig.UserApi.Secret.Sha256()) },
                    AllowOfflineAccess = true,//If you want to get refresh_tokens, AllowOfflineAccess must be set to true
                    AllowedScopes= {
                        OAuthConfig.UserApi.ApiName,
                        StandardScopes.OfflineAccess,
                    },
                    AccessTokenLifetime = OAuthConfig.ExpireIn,
                },

            };
        }

        /// <summary>
        ///Tested account and password
        /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetTestUsers()
        {
            return new List<TestUser>
            {
                new TestUser()
                {
                     SubjectId = "1",
                     Username = "test",
                     Password = "123456"
                },
            };
        }

        /// <summary>
        ///Test users of wechat openId
        /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetWeiXinOpenIdTestUsers()
        {
            return new List<TestUser>
            {
                new TestUser(){
                  SubjectId="owerhwroogs3902openId",
                }
            };
        }
    }

The complete Startup code is as follows:

 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 memory mode
            //services.AddIdentityServer()
            //    .AddDeveloperSigningCredential()
            //    .AddInMemoryApiResources(OAuthMemoryData.GetApiResources())
            //    .AddInMemoryClients(OAuthMemoryData.GetClients())
            //    .AddTestUsers(OAuthMemoryData.GetTestUsers());
            #endregion

            #region database storage mode
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddInMemoryApiResources(OAuthMemoryData.GetApiResources())
                //.AddInMemoryClients(OAuthMemoryData.GetClients())
                .AddClientStore<ClientStore>()
                .AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
                .AddExtensionGrantValidator<WeiXinOpenGrantValidator>();//Add verification of wechat custom mode
            #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();
            });
        }
    }

The code of the authorization center has basically been transformed. We use postman to access the authorization center, as shown in the following figure:

The access results already contain the relevant information such as refresh_token and access_token.

Let's access Api resources through access_token (the last two articles have relevant codes, and I'll check them before reading the last two articles). Here, I will directly carry access_token to visit, as shown in the figure:

Access successful!!

Let's refresh our token again, as shown in the figure below:

refresh_token succeeded.
Let's do a little test here. Test steps 4 and 5 in the authorization process above. Step 4 mentioned above is that when the client first requests the Api resource, it will ask the ids4 service gateway to obtain the authentication public key,
The successful acquisition will be returned to the Api resource and stored in memory. In the future, the authentication public key will not be obtained from the ids4 service

We stop the above authorization center (ids4 service gateway), and then use the previous access token to request Api resources, as shown in the following figure:

Now it has been confirmed that the authorization center (ids4 service gateway) is indeed stopped and cannot be accessed. Then, we can request Api resource gateway through the previously unexpired access [token], as shown in the following figure:



Perfect, the request is still successful, which fully proves that when the client requests the Api resource gateway (protected resource), the first time it receives the request, it will go to the authorization center (ids4 service gateway) to obtain the authentication public key and keep it in memory. The later request will not go to the authorization center to obtain the authentication public key, but the Api resource gateway (protected resource) will directly save it The authentication public key of is verified to pass the authorization.

Posted by Mutley on Mon, 23 Mar 2020 03:05:52 -0700