使用OpenIDConnect中间件,MVC客户端,Cookie

时间:2017-03-23 21:56:43

标签: identityserver4

使用Cookie时,有没有一种标准方法可以让使用ID4 OIDC中间件的MVC客户端刷新ClaimsPrincipal?如果要求中间件刷新ClaimsPrincipal会很好,但我不认为该功能存在。

下面的代码确实有效,但是,下面的示例中没有使用nonce - 所以我不确定这是否安全。我不确定中间件是如何创建现时的。

有没有人有一个使用带有ID4 OIDC中间件的cookie在MVC客户端应用程序中正确刷新ClaimsPrincipal的示例?

验证ID令牌并从ID令牌返回ClaimsPrincipal

private ClaimsPrincipal ValidateIdentityToken(string idToken, DiscoveryResponse disco  )
    {


        var keys = new List<SecurityKey>();
        foreach (var webKey in disco.KeySet.Keys)
        {
            var e = Base64Url.Decode(webKey.E);
            var n = Base64Url.Decode(webKey.N);

            var key = new RsaSecurityKey(new RSAParameters { Exponent = e, Modulus = n });
            key.KeyId = webKey.Kid;

            keys.Add(key);
        }

        var parameters = new TokenValidationParameters
        {
            ValidIssuer = disco.TryGetString(OidcConstants.Discovery.Issuer),
            ValidAudience = "mvc.hybrid",
            IssuerSigningKeys = keys,

            NameClaimType = JwtClaimTypes.Name,
            RoleClaimType = JwtClaimTypes.Role
        };

        var handler = new JwtSecurityTokenHandler();
        handler.InboundClaimTypeMap.Clear();

        SecurityToken token;
        var user = handler.ValidateToken(idToken, parameters, out token);

        //var nonce = user.FindFirst("nonce")?.Value ?? "";
        //if (!string.Equals(nonce, "random_nonce")) throw new Exception("invalid nonce");
       //nonce is always ""
        return user;
    }

检查Cookie过期时间。使用刷新令牌刷新ID和访问令牌。使用上述验证返回ClaimsPrincipal

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {


        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationScheme = "Cookies",
            AutomaticAuthenticate = true,
            ExpireTimeSpan = TimeSpan.FromMinutes(60),

            Events = new CookieAuthenticationEvents()
            {
                OnValidatePrincipal = async cookiecontext =>
                {
                    if (cookiecontext.Properties.Items.ContainsKey(".Token.expires_at"))
                    {
                        var expire = DateTime.Parse(cookiecontext.Properties.Items[".Token.expires_at"]);
                        if (expire <= DateTime.Now.AddMinutes(-5) || DateTime.Now > expire)
                        {
                            var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
                            if (disco.IsError) throw new Exception(disco.Error);


                            var refreshToken = cookiecontext.Properties.Items[".Token.refresh_token"];
                            var tokenClient = new TokenClient(disco.TokenEndpoint,
                                "mvc.hybrid",
                                "secret");
                            var response = await tokenClient.RequestRefreshTokenAsync(refreshToken);
                            if (!response.IsError)
                            {
                                cookiecontext.Properties.Items[".Token.access_token"] = response.AccessToken;
                                cookiecontext.Properties.Items[".Token.refresh_token"] = response.RefreshToken;
                                cookiecontext.Properties.Items[".Token.expires_at"] = DateTime.Now.AddSeconds((int)response.ExpiresIn).ToString();
                                cookiecontext.Properties.Items["NextAccessTokenRefresh"] = DateTime.Now.AddMinutes(5).ToString();

                                var _Princ = ValidateIdentityToken(response.IdentityToken, disco);

                                cookiecontext.ReplacePrincipal(_Princ);                                    

                                cookiecontext.ShouldRenew = true;

                            }
                            else
                            {
                                cookiecontext.RejectPrincipal();
                            }
                        }
                    }
                }
            }
        });

Wireup ID4中间件

 JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
        {
            AuthenticationScheme = "oidc",
            SignInScheme = "Cookies",

            Authority = "http://localhost:5000", 
            RequireHttpsMetadata = false,

            ClientId = "mvc.hybrid",
            ClientSecret = "secret",


            ResponseType = "code id_token",
            Scope = { "openid", "profile", "email", "api1", "offline_access", "role" },
            GetClaimsFromUserInfoEndpoint = true,
            Events = new OpenIdConnectEvents()
            {
                OnTicketReceived = notification =>
                {
                    notification.Response.Cookies.Append("NextAccessTokenRefresh", DateTime.Now.AddMinutes(5).ToString());
                    return Task.FromResult(0);
                }
            },

            SaveTokens = true,

            TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
            {
                NameClaimType = JwtClaimTypes.Name,
                RoleClaimType = JwtClaimTypes.Role,
            }
        });


    }

0 个答案:

没有答案