[英]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.