通过ASP.NET Core MVC中的refresh_token静默续订access_token [英] Silent renew access_token via refresh_token in asp.net core mvc

查看:139
本文介绍了通过ASP.NET Core MVC中的refresh_token静默续订access_token的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题出在客户端部分的自动更新访问令牌中.下一个状态是:在客户端(MVC)控制器上,我添加了authorize属性,由于客户端使用会话cookie进行身份验证,所以它传递的很好,然后在服务器(Web API应用)上发送了请求.服务器验证令牌并说它已经过期.如何在客户端中续订访问令牌 请参阅MVC启动文件:

The problem is in automatic update access token in client part. There is next state: on client (MVC) controller I added authorize attribute and it passed well because the client use session cookie for authentication, then request is sent on server (Web API app). The server validate token and says that it has been expired. How I can renew access token in client Please see MVC Startup file:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddAutoMapper(typeof(MappingProfile).Assembly);
        // Added for session state
        services.AddDistributedMemoryCache();

        services.AddSession();
        services
            .AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;

            })
            .AddCookie("Cookies")
            .AddOpenIdConnect(options =>
            {
                options.MetadataAddress = Configuration["oidc:metadataAddress"];
                options.SignInScheme = "Cookies";
                options.ClientId = Configuration["oidc:clientId"];
                options.ClientSecret = Configuration["oidc:clientSecret"];
                options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
                options.CallbackPath = "/oidc-callback";
                options.GetClaimsFromUserInfoEndpoint = true;
                options.Scope.Add("openid");
                options.Scope.Add("email");
                options.Scope.Add("profile");
                options.TokenValidationParameters = new TokenValidationParameters()
                {
                    NameClaimType = "name",
                    ValidateAudience = false,
                    RoleClaimType = "role"
                };
                options.Events = new OpenIdConnectEvents
                {
                    OnTokenResponseReceived = async context=>
                    {
                        var user = context.Principal;
                        var identity = user.Identity as ClaimsIdentity;
                        var claim = new Claim("access_token", context.TokenEndpointResponse.AccessToken);
                        identity?.AddClaim(claim);
                        await Task.CompletedTask;
                    },

                };
            });
        services.AddHttpContextAccessor();
        services.AddReportServerClient();
    }

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

        //app.UseExceptionHandlers();

        app.UseStaticFiles();

        app.UseAuthentication();


        app.UseSession();

        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            RequireHeaderSymmetry = true,
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });

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

也尝试对OpenIdConnectOptions使用UseTokenLifeTime,但是这种情况不起作用. 当我在浏览器中删除Cookie并刷新页面时,它将转到Auth provider并给我有效的令牌 也尝试过

Also tried UseTokenLifeTime for OpenIdConnectOptions, but this case doesn't work. When I remove cookie in browser and refresh the page it goes to Auth provider and give me valid token also tried

services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            })

推荐答案

您可以使用多种方式刷新访问令牌,下面我将说明如何使用ASPNET Core中的中间件来访问访问令牌.

You can refresh an access token using multiple ways, Below I will illustrate how you can an access token using middleware in ASPNET Core.

在您的启动类中,在Configure方法中添加以下行,该行将在到期时更新访问令牌.注意:请在"app.UseAuthentication()"之后添加.

In you startup class, in the the Configure method add the following line that will renew an access token when it is near expiration. NB add after "app.UseAuthentication()".

app.UseMiddleware<CheckAccessTokenValidityMiddleware>();

创建一个扩展方法,该方法将在访问令牌到期时自动更新,如下所述

Create an extension method that will automatically renew the access token as it nears expiration as follows

public class CheckAccessTokenValidityMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IConfiguration _configuration;

    public CheckAccessTokenValidityMiddleware(RequestDelegate next, IConfiguration configuration)
    {
        _next = next;
        _configuration = configuration;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var expireAt = await context.GetTokenAsync("expires_at");
        if (expireAt != null)
        {
            var dateExpireAt = DateTime.Parse(expireAt, null, DateTimeStyles.RoundtripKind);
            if(dateExpireAt != null)
            {
                if ((dateExpireAt - DateTime.Now).TotalMinutes < 10)
                {
                    var discoveryClient = new DiscoveryClient(_configuration["OIDC:Authority"]);
                    discoveryClient.Policy.RequireHttps = false;
                    var discovery = await discoveryClient.GetAsync();
                    if (!discovery.IsError)
                    {
                        using (var tokenClient = new TokenClient(discovery.TokenEndpoint, ClientConstants.KodelessClientId, ClientConstants.KodelessClientSecret))
                        {
                            var refreshToken = await context.GetTokenAsync("refresh_token");
                            var tokenResult = await tokenClient.RequestRefreshTokenAsync(refreshToken);
                            if (!tokenResult.IsError)
                            {
                                var newIdToken = tokenResult.IdentityToken;
                                var newAccessToken = tokenResult.AccessToken;
                                var newRefreshToken = tokenResult.RefreshToken;
                                var tokens = new List<AuthenticationToken>
                                {
                                    new AuthenticationToken {Name = OpenIdConnectParameterNames.IdToken, Value = newIdToken},
                                    new AuthenticationToken
                                    {
                                        Name = OpenIdConnectParameterNames.AccessToken,
                                        Value = newAccessToken
                                    },
                                    new AuthenticationToken
                                    {
                                        Name = OpenIdConnectParameterNames.RefreshToken,
                                        Value = newRefreshToken
                                    }
                                };
                                var expiresAt = DateTime.Now + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
                                tokens.Add(new AuthenticationToken
                                {
                                    Name = "expires_at",
                                    Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
                                });
                                var info = await context.AuthenticateAsync(AuthenticationConstants.Cookies);
                                info.Properties.StoreTokens(tokens);
                                await context.SignInAsync(AuthenticationConstants.Cookies, info.Principal, info.Properties);
                            }
                            else
                            {
                                await context.SignOutAsync(AuthenticationConstants.Cookies);
                                await context.SignOutAsync(AuthenticationConstants.Oidc);
                            }
                        }
                    }
                }
            }
        }
        await _next.Invoke(context);
    }
}

这篇关于通过ASP.NET Core MVC中的refresh_token静默续订access_token的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆