简体   繁体   English

使用IdentityServer3 + Entity Framework进行令牌验证

[英]Token validation with IdentityServer3 + Entity Framework

I am using Identity Server 3 with Entity Framework. 我将Identity Server 3与Entity Framework一起使用。 My ASP.NET MVC app logs in to the SSO/IdentityServer app using below configuration and then that access token is saved in a cookie which is used by javascript to call our API. 我的ASP.NET MVC应用程序使用以下配置登录到SSO / IdentityServer应用程序,然后该访问令牌保存在cookie中,javascript使用此cookie来调用我们的API。

Problem is when I login to my ASP.NET MVC app then I go to database and delete that token from the database table, then my API says invalid bearer token as expected, but when I the refresh page in the ASP.NET MVC app, it still shows as logged in and I think it's because of cookie configuration. 问题是,当我登录到ASP.NET MVC应用程序时,我进入数据库并从数据库表中删除该令牌,然后我的API如预期的那样显示了无效的承载令牌,但是当我在ASP.NET MVC应用程序中刷新页面时,它仍然显示为已登录,我认为这是由于Cookie配置所致。

How can I ask MVC app to always validate token from server? 如何要求MVC应用始终验证来自服务器的令牌?

AuthConfig.cs of ASP.NET MVC application: ASP.NET MVC应用程序的AuthConfig.cs

public static class AuthConfig
{
        public static void RegisterAuth(IAppBuilder app)
        {
            ServicePointManager.ServerCertificateValidationCallback =
                (sender, certificate, chain, sslPolicyErrors) => true;

            JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "Cookies",
                SlidingExpiration = true,
                ExpireTimeSpan = SellutionConstants.Globals.AccessTokenExpirationTimeSpan
            });

            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = "sellutionapp",
                Authority = SsoConfigHelper.SellutionSts,
                ResponseType = "code id_token",
                Scope = "openid profile roles all_claims " + SsoConfigHelper.SellutionApiScope,
                UseTokenLifetime = false,

                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role",
                },

                SignInAsAuthenticationType = "Cookies",

                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthorizationCodeReceived = async n =>
                    {
                        // use the code to get the access and refresh token
                        var tokenClient = new TokenClient(
                            SsoConfigHelper.SellutionStsTokenEndpoint,
                            "sellutionapp",
                            "secret");

                        if (String.IsNullOrEmpty(n.RedirectUri))
                        {
                            n.RedirectUri = n.Request.Scheme + "://" + n.Request.Host + n.Request.PathBase;
                        }

                        var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);
                        if (tokenResponse.IsError)
                        {
                            throw new Exception(tokenResponse.Error);
                        }


                        // use the access token to retrieve claims from userinfo
                        var userInfoClient = new UserInfoClient(
                        new Uri(SsoConfigHelper.SellutionStsUserInfoEndpoint),
                        tokenResponse.AccessToken);

                        var userInfoResponse = await userInfoClient.GetAsync();

                        // create new identity
                        var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
                        id.AddClaims(userInfoResponse.GetClaimsIdentity().Claims);

                        id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
                        id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
                        //id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
                        id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
                        id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));

                        LoginCookieHelper.SetUserData(tokenResponse.AccessToken);
                        n.AuthenticationTicket = new AuthenticationTicket(
                            new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
                            n.AuthenticationTicket.Properties);
                    },

                    RedirectToIdentityProvider = n =>
                    {

                        // This ensures that the address used for sign in and sign out is picked up dynamically from the request
                        // this allows you to deploy the app (to Azure Web Sites, for example) without having to change settings.
                        var appBaseUrl = n.Request.Scheme + "://" + n.Request.Host + n.Request.PathBase;
                        n.ProtocolMessage.RedirectUri = appBaseUrl;
                        n.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;

                        // if signing out, add the id_token_hint
                        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
                        {
                            var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                            if (idTokenHint != null)
                            {
                                n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                            }
                        }

                        return Task.FromResult(0);
                    }
                }
            });
        }
}

Identity server configuration: 身份服务器配置:

class Factory
{
        public static IdentityServerServiceFactory Configure()
        {
            var efConfig = new EntityFrameworkServiceOptions
            {
                ConnectionString = "DefaultConnection",

            };

            // these two calls just pre-populate the test DB from the in-memory config
            ConfigureClients(Clients.Get(), efConfig);
            ConfigureScopes(Scopes.Get(), efConfig);

            var factory = new IdentityServerServiceFactory();

            //var scopeStore = new InMemoryScopeStore(Scopes.Get());
            //factory.ScopeStore = new Registration<IScopeStore>(scopeStore);
            //var clientStore = new InMemoryClientStore(Clients.Get());
            //factory.ClientStore = new Registration<IClientStore>(clientStore);

            factory.CorsPolicyService = new Registration<ICorsPolicyService>(new DefaultCorsPolicyService { AllowAll = true });

            factory.RegisterOperationalServices(efConfig);
            factory.RegisterConfigurationServices(efConfig);

            return factory;
        }


        public static void ConfigureClients(IEnumerable<Client> clients, EntityFrameworkServiceOptions options)
        {
            using (var db = new ClientConfigurationDbContext(options.ConnectionString, options.Schema))
            {
                if (!db.Clients.Any())
                {
                    foreach (var c in clients)
                    {
                        var e = c.ToEntity();
                        db.Clients.Add(e);
                    }
                    db.SaveChanges();
                }
            }
        }

        public static void ConfigureScopes(IEnumerable<Scope> scopes, EntityFrameworkServiceOptions options)
        {
            using (var db = new ScopeConfigurationDbContext(options.ConnectionString, options.Schema))
            {
                if (!db.Scopes.Any())
                {
                    foreach (var s in scopes)
                    {
                        var e = s.ToEntity();
                        db.Scopes.Add(e);
                    }
                    db.SaveChanges();
                }
            }
        }
}

IdentityServer client configuration IdentityServer客户端配置

public class Clients
{
        public static List<Client> Get()
        {
            return new List<Client>
            {
                 new Client
                 {
                    ClientName = "Resource Owner Flow",
                    ClientId = "resourceowner",
                    ClientSecrets = new List<Secret> {new Secret("vkgk8M4pj".Sha256())},
                    Flow = Flows.ResourceOwner  , //Password authentication
                    PrefixClientClaims = false,
                    AccessTokenType = AccessTokenType.Jwt,
                    AllowedScopes = new List<string>
                    {
                        Constants.StandardScopes.OpenId,
                        Constants.StandardScopes.Profile,
                        Constants.StandardScopes.Email,
                        Constants.StandardScopes.Roles,
                        Constants.StandardScopes.Address,
                        Constants.StandardScopes.AllClaims,
                        Constants.StandardScopes.OfflineAccess,
                        SsoConfigHelper.SellutionApiScope
                    },
                   RequireConsent = false,
                   AllowRememberConsent = true,
                   LogoutSessionRequired = true,

                   RefreshTokenExpiration = TokenExpiration.Absolute,
                   RefreshTokenUsage = TokenUsage.OneTimeOnly,
                   UpdateAccessTokenClaimsOnRefresh = true,
                   AbsoluteRefreshTokenLifetime =(int)TimeSpan.FromDays(1).TotalSeconds
                },

                /////////////////////////////////////////////////////////////
                // MVC OWIN Implicit Client
                /////////////////////////////////////////////////////////////
                new Client
                {
                    ClientName = "Sellution Application",
                    ClientId = "sellutionapp",
                    Flow = Flows.Hybrid,
                    AllowAccessTokensViaBrowser = false,

                    AllowedScopes = new List<string>
                    {
                        Constants.StandardScopes.OpenId,
                        Constants.StandardScopes.Profile,
                        Constants.StandardScopes.Email,
                        Constants.StandardScopes.Roles,
                        Constants.StandardScopes.Address,
                        Constants.StandardScopes.AllClaims,
                        SsoConfigHelper.SellutionApiScope
                    },
                     ClientSecrets = new List<Secret>
                    {
                        new Secret("secret".Sha256())
                    },

                    AccessTokenType = AccessTokenType.Reference,
                    RequireConsent = false,
                    AllowRememberConsent = true,
                    LogoutSessionRequired = true,
                },

            };
        }
}

You need to sign the user out of the MVC application as well because according to your code you are using Cookie Authentication named Cookies you also have to do a sign out on that authentication scheme when they log out (not deleteing the token in the store). 您还需要将用户从MVC应用程序中注销,因为根据您的代码,您正在使用名为Cookies Cookie身份验证,您还必须在注销时在该身份验证方案上进行注销(而不是删除商店中的令牌)。 。

AuthenticationManager.SignOut("Cookies"); is what your controller action will require for logout. 这是您的控制器操作将需要注销的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM