Identity Server 在生产环境中清空 cookie
Identity Server empty cookies on production
我有一个 Identity Server 4 应用,Angular 客户端使用 oidc-client。问题是在生产中,方法 addUserSignedOut
在我登录客户端后不会停止被调用。我在本地测试它并且工作正常。
我认为问题可能与部署时不存在的 cookie 有关。我检查了 checksession
getCookies()
方法,登录后 cookie 为空 (document.cookie = ""
),知道如何解决这个问题吗?
这是我的 IDP 代码:
public void ConfigureServices(IServiceCollection services)
{
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDataProtection()
.AddKeyManagementOptions(dp => dp.NewKeyLifetime = TimeSpan.FromDays(90));
//.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
//.ProtectKeysWithAzureKeyVault("<keyIdentifier>", "<clientId>", "<clientSecret>");
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
services.AddIdentity<ApplicationUser, IdentityRole>(options => {
options.Password.RequiredLength = 6; // Passwords must be at least 6 characters
options.Password.RequireLowercase = true; // Passwords must have at least one lowercase ('a'-'z')
options.Password.RequireUppercase = true; // Passwords must have at least one uppercase ('A'-'Z')
options.Password.RequireDigit = true; // Passwords must have at least one digit ('0'-'9')
options.Password.RequireNonAlphanumeric = true; // Passwords must have at least one non alphanumeric character
options.Password.RequiredUniqueChars = 1; // Passwords must use at least 1 different characters
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1).AddXmlSerializerFormatters();
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
services.AddTransient<IProfileService, ProfileService>();
var builder = services.AddIdentityServer(
options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
}
)
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
});
// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));
builder.Services.Configure<SecurityStampValidatorOptions>(opts =>
{
opts.OnRefreshingPrincipal = SecurityStampValidatorCallback.UpdatePrincipal;
});
services.AddAuthentication(options => {
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", opts =>
{
opts.SlidingExpiration = true;
opts.ExpireTimeSpan = TimeSpan.FromMinutes(15);
});
if (Environment.IsDevelopment() || Environment.EnvironmentName == "local" )
{
builder.AddDeveloperSigningCredential();
}
else
{
X509Certificate2 cert = null;
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
Configuration.GetSection("Certificate").GetValue<string>("thumbprint"),
false);
// Get the first cert with the thumbprint
if (certCollection.Count > 0)
{
cert = certCollection[0];
Log.Logger.Information($"Successfully loaded cert from registry: {cert.Thumbprint}");
}
}
// Fallback to local file for development
if (cert == null)
{
throw new Exception("Cannot find any Certificate");
}
builder.AddSigningCredential(cert);
}
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment() || Environment.EnvironmentName == "local")
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();//SSO
}
app.UseHttpsRedirection();//SSO
app.UseStaticFiles();
app.UseCookiePolicy();//SSO
app.UseIdentityServer();
app.UseAuthentication();//SSO
app.UseSaml();// Use SAML middleware.
app.UseMvcWithDefaultRoute();
}
IDP 注销控制器:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
// build a model so the logged out page knows what to display
var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);
if (User?.Identity.IsAuthenticated == true)
{
// Request logout at the service provider(SAML).
await InitiateSingleLogout();
// delete local authentication cookie
await _signInManager.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
if (vm.PostLogoutRedirectUri != null) {
return Redirect(vm.PostLogoutRedirectUri);
}
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
SAML 注销:
private async Task InitiateSingleLogout()
{
var ssoState = await _samlIdentityProvider.GetStatusAsync();
if (await ssoState.CanSloAsync())
{
// Request logout at the service provider(s).
await _samlIdentityProvider.InitiateSloAsync();
}
}
Angular 客户端 oidc-客户端设置:
const settings: any = {
authority: `${environment.identity_server_url}`,
client_id: 'js',
redirect_uri: `${environment.login_redirect}/signin-oidc`,
response_type: 'id_token token',
scope: 'openid profile salesforce api1',
post_logout_redirect_uri: `${environment.login_redirect}`,
userStore: new WebStorageStateStore({ store: window.localStorage }),
silent_redirect_uri: `${environment.login_redirect}/signin-oidc-silent`,
// automaticSilentRenew: true
};
处理注销事件:
this.mgr.events.addUserSignedOut(() => {
this.startSigninMainWindow({ external_logout: true })
})
这是我的守卫,我在这里检查用户是否登录并调用 signinRedirect()
:
export class AuthGuardService implements CanActivate {
constructor(
private authService: AuthService
) { }
canActivate() {
const isLoggedIn = this.authService.isLoggedInObs();
isLoggedIn.subscribe(loggedin => {
if (!loggedin) {
this.authService.startSigninMainWindow();
}
});
return isLoggedIn;
}
}
这是 AuthService
class 所有关于 oidc-client 的逻辑所在。
export class AuthService {
mgr: UserManager = new UserManager(settings);
userLoadededEvent: EventEmitter<User> = new EventEmitter<User>();
currentUser: User;
loggedIn = false;
authHeaders: Headers;
private accountID: string;
private accountToken: string;
private internInfoSubject = new BehaviorSubject<InternUser>(null);
public readonly internInfo$ = this.internInfoSubject
.asObservable()
.pipe(
filter(user => user !== null),
distinctUntilChanged()
);
constructor(
private router: Router,
private internPortalService: InternPortalService,
private apiService: ApiService,
private http: HttpClient
) {
this.mgr.events.addUserSignedOut(() => {
this.startSigninMainWindow({ external_logout: true })
})
}
getUser() {
this.mgr
.getUser()
.then(user => {
console.log('got user', user);
this.currentUser = user;
this.userLoadededEvent.emit(user);
})
.catch(function(err) {
console.log(err);
});
}
startSigninMainWindow(query = {}) {
this.mgr.signinRedirect({extraQueryParams: query});
}
endSigninMainWindow() {
this.mgr
.signinRedirectCallback()
.then(user => {
console.log('signed in', user);
this.currentUser = user;
this.setLocalStorage();
})
.catch(function(err) {
console.log(err);
});
}
endSigninSilentMainWindow() {
this.mgr
.signinSilentCallback()
.then(() => {
console.log('end silent signed in');
})
.catch(function(err) {
console.log(err);
});
}
changePassword(): Observable<any> {
const params = new HttpParams()
.set('userId', this.currentUser.profile.sub)
.set('passwordAction', '2')
.set('redirectUrl', window.location.href);
return this.apiService.getIdentityServer('/Token', params);
}
startSignoutMainWindow() {
this.mgr
.signoutRedirect()
.then(function(resp) {
console.log('signed out', resp);
// setTimeout(5000, () => {
// console.log('testing to see if fired...');
// });
})
.catch(function(err) {
console.log(err);
});
}
isLoggedInObs(): Observable<boolean> {
return observableFrom(this.mgr.getUser()).pipe(
map<User, boolean>(user => {
if (user) {
if (!this.internPortalService.getAccountId()) {
this.currentUser = user;
this.setLocalStorage();
}
return true;
} else {
return false;
}
})
);
}
onSignOut(callback: Function){
this.mgr.events.addUserSignedOut(resp => {
console.log("user signed out");
callback();
});
}
get authenticationInfo(): InternUser {
return this.internInfoSubject.value;
}
private setLocalStorage() {
this.accountID = this.currentUser.profile.account_id;
this.accountToken = this.currentUser.access_token;
this.internPortalService.setAccountId(this.accountID, this.accountToken);
this.internPortalService
.getIntern()
.subscribe(res => this.updateToken(res));
}
updateToken(internUser: any): void {
console.log(internUser);
if (!internUser) {
return;
}
// TODO: Refactor once BE migration is completed
internUser.auth = this.currentUser;
internUser.state_locales = this.internPortalService.getStateLocales(
internUser.state
);
this.internInfoSubject.next(internUser);
this.router.navigate(['/intern-portal']);
}
// TODO: To be removed after QA
public updateLocale(counter: number): void {
const stateList = ['TX', 'MI', 'AZ', 'NC', 'SC', 'FL', 'NV', 'IN'];
const newUser = this.authenticationInfo;
newUser.state = stateList[counter];
newUser.state_locales = this.internPortalService.getStateLocales(
newUser.state
);
console.log(`An user from: ${newUser.state_locales.state} was loaded`);
this.internInfoSubject.next(newUser);
}
logout(): void {
localStorage.clear();
this.internInfoSubject.next(null);
}
}
和 signin-oidc-silent
组件:
export class SigninOidcComponent implements OnInit {
private element: any;
constructor(private authService: AuthService) {
}
ngOnInit() {
console.log('init oidc logic');
this.authService.endSigninMainWindow();
}
}
我只是不知道为什么托管应用程序会出现无限循环。实际上,如果我在本地使用客户端并指向我托管的 IDP,我会得到相同的无限循环。
我在控制台上没有看到任何错误,只有这个警告 ResponseValidator._processSigninParams: Response was error login_required
这里是一些 IDP 日志:
2019-04-15 11:16:49.383 +00:00 [DBG] Request path /connect/authorize matched to endpoint type Authorize
2019-04-15 11:16:49.418 +00:00 [DBG] Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint
2019-04-15 11:16:49.419 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
2019-04-15 11:16:49.423 +00:00 [DBG] Start authorize request
2019-04-15 11:16:49.435 +00:00 [DBG] User in authorize request: cfd7214d-305d-4d91-9d50-671dac6b37d8
2019-04-15 11:16:49.436 +00:00 [DBG] Start authorize request protocol validation
2019-04-15 11:16:49.566 +00:00 [DBG] js found in database: true
2019-04-15 11:16:49.569 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:49.624 +00:00 [DBG] Found ["openid","profile","salesforce"] identity scopes in database
2019-04-15 11:16:49.673 +00:00 [DBG] Found ["api1"] API scopes in database
2019-04-15 11:16:49.687 +00:00 [DBG] Found ["openid","profile","salesforce"] identity scopes in database
2019-04-15 11:16:49.703 +00:00 [DBG] Found ["api1"] API scopes in database
2019-04-15 11:16:49.712 +00:00 [DBG] Calling into custom validator: IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator
2019-04-15 11:16:49.755 +00:00 [INF] ValidatedAuthorizeRequest
{"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","ResponseType":"id_token token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid profile salesforce api1","State":"42a8d9eda2a94c61a4f8ac2f13bbee52","UiLocales":null,"Nonce":"76c3d45a35524c908b1593454305a796","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":null,"MaxAge":null,"LoginHint":null,"SessionId":"a593b46f1553fa4d5beae979ec6475ba","Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","response_type":"id_token token","scope":"openid profile salesforce api1","state":"42a8d9eda2a94c61a4f8ac2f13bbee52","nonce":"76c3d45a35524c908b1593454305a796","external_logout":"true"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:49.758 +00:00 [DBG] Client is configured to not require consent, no consent is required
2019-04-15 11:16:49.759 +00:00 [DBG] Creating Implicit Flow response.
2019-04-15 11:16:49.760 +00:00 [DBG] Getting claims for access token for client: js
2019-04-15 11:16:49.765 +00:00 [DBG] Getting claims for access token for subject: cfd7214d-305d-4d91-9d50-671dac6b37d8
2019-04-15 11:16:49.769 +00:00 [DBG] Claim types from profile service that were filtered: ["sub","idp","amr","auth_time"]
2019-04-15 11:16:49.812 +00:00 [DBG] Getting claims for identity token for subject: cfd7214d-305d-4d91-9d50-671dac6b37d8 and client: js
2019-04-15 11:16:49.814 +00:00 [DBG] In addition to an id_token, an access_token was requested. No claims other than sub are included in the id_token. To obtain more user claims, either use the user info endpoint or set AlwaysIncludeUserClaimsInIdToken on the client configuration.
2019-04-15 11:16:49.835 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","Endpoint":"Authorize","SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","Scopes":"openid profile salesforce api1","GrantType":"implicit","Tokens":[{"TokenType":"id_token","TokenValue":"****UIMg","$type":"Token"},{"TokenType":"access_token","TokenValue":"****NWSw","$type":"Token"}],"Category":"Token","Name":"Token Issued Success","EventType":"Success","Id":2000,"Message":null,"ActivityId":"0HLLVFNQC24O5:00000001","TimeStamp":"2019-04-15T11:16:49.0000000Z","ProcessId":11056,"LocalIpAddress":"127.0.0.1:28158","RemoteIpAddress":"167.57.108.74","$type":"TokenIssuedSuccessEvent"}
2019-04-15 11:16:49.845 +00:00 [INF] Authorize endpoint response
{"SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","ClientId":"js","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","State":"42a8d9eda2a94c61a4f8ac2f13bbee52","Scope":"openid profile salesforce api1","Error":null,"ErrorDescription":null,"$type":"AuthorizeResponseLog"}
2019-04-15 11:16:56.059 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.067 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.069 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.071 +00:00 [DBG] Request path /.well-known/openid-configuration matched to endpoint type Discovery
2019-04-15 11:16:56.076 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
2019-04-15 11:16:56.077 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
2019-04-15 11:16:56.079 +00:00 [DBG] Start discovery request
2019-04-15 11:16:56.118 +00:00 [DBG] Found ["openid","profile","salesforce","role","api1"] as all scopes in database
2019-04-15 11:16:56.341 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.347 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.349 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.350 +00:00 [DBG] Request path /.well-known/openid-configuration matched to endpoint type Discovery
2019-04-15 11:16:56.351 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
2019-04-15 11:16:56.352 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
2019-04-15 11:16:56.353 +00:00 [DBG] Start discovery request
2019-04-15 11:16:56.374 +00:00 [DBG] Found ["openid","profile","salesforce","role","api1"] as all scopes in database
2019-04-15 11:16:56.381 +00:00 [DBG] Request path /connect/checksession matched to endpoint type Checksession
2019-04-15 11:16:56.389 +00:00 [DBG] Endpoint enabled: Checksession, successfully created handler: IdentityServer4.Endpoints.CheckSessionEndpoint
2019-04-15 11:16:56.390 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.CheckSessionEndpoint for /connect/checksession
2019-04-15 11:16:56.392 +00:00 [DBG] Rendering check session result
2019-04-15 11:16:56.613 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration/jwks from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.618 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.621 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.622 +00:00 [DBG] Request path /.well-known/openid-configuration/jwks matched to endpoint type Discovery
2019-04-15 11:16:56.624 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryKeyEndpoint
2019-04-15 11:16:56.625 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryKeyEndpoint for /.well-known/openid-configuration/jwks
2019-04-15 11:16:56.628 +00:00 [DBG] Start key discovery request
2019-04-15 11:16:56.719 +00:00 [DBG] Request path /connect/authorize matched to endpoint type Authorize
2019-04-15 11:16:56.722 +00:00 [DBG] Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint
2019-04-15 11:16:56.723 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
2019-04-15 11:16:56.725 +00:00 [DBG] Start authorize request
2019-04-15 11:16:56.726 +00:00 [DBG] No user present in authorize request
2019-04-15 11:16:56.727 +00:00 [DBG] Start authorize request protocol validation
2019-04-15 11:16:56.743 +00:00 [DBG] js found in database: true
2019-04-15 11:16:56.748 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:56.757 +00:00 [DBG] Found ["openid"] identity scopes in database
2019-04-15 11:16:56.760 +00:00 [DBG] Found [] API scopes in database
2019-04-15 11:16:56.767 +00:00 [DBG] Found ["openid"] identity scopes in database
2019-04-15 11:16:56.772 +00:00 [DBG] Found [] API scopes in database
2019-04-15 11:16:56.773 +00:00 [DBG] Calling into custom validator: IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator
2019-04-15 11:16:56.775 +00:00 [INF] ValidatedAuthorizeRequest
{"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"anonymous","ResponseType":"id_token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid","State":"170ef6a2eda34bc6a7c0a5d79fc25a7a","UiLocales":null,"Nonce":"1f0b1599850a4c6882f9e69ceda252ee","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":"none","MaxAge":null,"LoginHint":null,"SessionId":null,"Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","response_type":"id_token","scope":"openid","state":"170ef6a2eda34bc6a7c0a5d79fc25a7a","nonce":"1f0b1599850a4c6882f9e69ceda252ee","prompt":"none"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:56.776 +00:00 [INF] Showing error: prompt=none was requested but user is not authenticated
2019-04-15 11:16:56.778 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"anonymous","ResponseType":"id_token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid","State":"170ef6a2eda34bc6a7c0a5d79fc25a7a","UiLocales":null,"Nonce":"1f0b1599850a4c6882f9e69ceda252ee","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":"none","MaxAge":null,"LoginHint":null,"SessionId":null,"Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","response_type":"id_token","scope":"openid","state":"170ef6a2eda34bc6a7c0a5d79fc25a7a","nonce":"1f0b1599850a4c6882f9e69ceda252ee","prompt":"none"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:56.779 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","Endpoint":"Authorize","SubjectId":null,"Scopes":"openid","GrantType":"implicit","Error":"login_required","ErrorDescription":null,"Category":"Token","Name":"Token Issued Failure","EventType":"Failure","Id":2001,"Message":null,"ActivityId":"0HLLVFNQC24O6:00000002","TimeStamp":"2019-04-15T11:16:56.0000000Z","ProcessId":11056,"LocalIpAddress":"127.0.0.1:28158","RemoteIpAddress":"167.57.108.74","$type":"TokenIssuedFailureEvent"}
2019-04-15 11:16:57.174 +00:00 [DBG] CORS request made for path: /connect/userinfo from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:57.178 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:57.179 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:57.180 +00:00 [DBG] Request path /connect/userinfo matched to endpoint type Userinfo
2019-04-15 11:16:57.185 +00:00 [DBG] Endpoint enabled: Userinfo, successfully created handler: IdentityServer4.Endpoints.UserInfoEndpoint
2019-04-15 11:16:57.186 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.UserInfoEndpoint for /connect/userinfo
2019-04-15 11:16:57.188 +00:00 [DBG] Start userinfo request
2019-04-15 11:16:57.189 +00:00 [DBG] Bearer token found in header
2019-04-15 11:16:57.240 +00:00 [DBG] js found in database: true
2019-04-15 11:16:57.241 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:57.269 +00:00 [DBG] js found in database: true
2019-04-15 11:16:57.270 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:57.281 +00:00 [DBG] Calling into custom token validator: IdentityServer4.Validation.DefaultCustomTokenValidator
2019-04-15 11:16:57.283 +00:00 [DBG] Token validation success
我终于找到了为 cookie 设置 SameSite.None
的位置,以便浏览器在检查会话状态时将其发送回 IS。在我的例子中,我使用 ASP.NET Core Identity
所以代码是:
builder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.IsEssential = true;
// we need to disable to allow iframe for authorize requests
options.Cookie.SameSite = AspNetCore.Http.SameSiteMode.None;
});
之后:
var builder = services.AddIdentityServer(options =>
...
我有一个 Identity Server 4 应用,Angular 客户端使用 oidc-client。问题是在生产中,方法 addUserSignedOut
在我登录客户端后不会停止被调用。我在本地测试它并且工作正常。
我认为问题可能与部署时不存在的 cookie 有关。我检查了 checksession
getCookies()
方法,登录后 cookie 为空 (document.cookie = ""
),知道如何解决这个问题吗?
这是我的 IDP 代码:
public void ConfigureServices(IServiceCollection services)
{
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDataProtection()
.AddKeyManagementOptions(dp => dp.NewKeyLifetime = TimeSpan.FromDays(90));
//.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>"))
//.ProtectKeysWithAzureKeyVault("<keyIdentifier>", "<clientId>", "<clientSecret>");
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));
services.AddIdentity<ApplicationUser, IdentityRole>(options => {
options.Password.RequiredLength = 6; // Passwords must be at least 6 characters
options.Password.RequireLowercase = true; // Passwords must have at least one lowercase ('a'-'z')
options.Password.RequireUppercase = true; // Passwords must have at least one uppercase ('A'-'Z')
options.Password.RequireDigit = true; // Passwords must have at least one digit ('0'-'9')
options.Password.RequireNonAlphanumeric = true; // Passwords must have at least one non alphanumeric character
options.Password.RequiredUniqueChars = 1; // Passwords must use at least 1 different characters
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1).AddXmlSerializerFormatters();
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
services.AddTransient<IProfileService, ProfileService>();
var builder = services.AddIdentityServer(
options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
}
)
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b =>
b.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
});
// Add SAML SSO services.
services.AddSaml(Configuration.GetSection("SAML"));
builder.Services.Configure<SecurityStampValidatorOptions>(opts =>
{
opts.OnRefreshingPrincipal = SecurityStampValidatorCallback.UpdatePrincipal;
});
services.AddAuthentication(options => {
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", opts =>
{
opts.SlidingExpiration = true;
opts.ExpireTimeSpan = TimeSpan.FromMinutes(15);
});
if (Environment.IsDevelopment() || Environment.EnvironmentName == "local" )
{
builder.AddDeveloperSigningCredential();
}
else
{
X509Certificate2 cert = null;
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
Configuration.GetSection("Certificate").GetValue<string>("thumbprint"),
false);
// Get the first cert with the thumbprint
if (certCollection.Count > 0)
{
cert = certCollection[0];
Log.Logger.Information($"Successfully loaded cert from registry: {cert.Thumbprint}");
}
}
// Fallback to local file for development
if (cert == null)
{
throw new Exception("Cannot find any Certificate");
}
builder.AddSigningCredential(cert);
}
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment() || Environment.EnvironmentName == "local")
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();//SSO
}
app.UseHttpsRedirection();//SSO
app.UseStaticFiles();
app.UseCookiePolicy();//SSO
app.UseIdentityServer();
app.UseAuthentication();//SSO
app.UseSaml();// Use SAML middleware.
app.UseMvcWithDefaultRoute();
}
IDP 注销控制器:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
// build a model so the logged out page knows what to display
var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);
if (User?.Identity.IsAuthenticated == true)
{
// Request logout at the service provider(SAML).
await InitiateSingleLogout();
// delete local authentication cookie
await _signInManager.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
if (vm.PostLogoutRedirectUri != null) {
return Redirect(vm.PostLogoutRedirectUri);
}
// since we don't have a valid context, then we just go back to the home page
return Redirect("~/");
}
SAML 注销:
private async Task InitiateSingleLogout()
{
var ssoState = await _samlIdentityProvider.GetStatusAsync();
if (await ssoState.CanSloAsync())
{
// Request logout at the service provider(s).
await _samlIdentityProvider.InitiateSloAsync();
}
}
Angular 客户端 oidc-客户端设置:
const settings: any = {
authority: `${environment.identity_server_url}`,
client_id: 'js',
redirect_uri: `${environment.login_redirect}/signin-oidc`,
response_type: 'id_token token',
scope: 'openid profile salesforce api1',
post_logout_redirect_uri: `${environment.login_redirect}`,
userStore: new WebStorageStateStore({ store: window.localStorage }),
silent_redirect_uri: `${environment.login_redirect}/signin-oidc-silent`,
// automaticSilentRenew: true
};
处理注销事件:
this.mgr.events.addUserSignedOut(() => {
this.startSigninMainWindow({ external_logout: true })
})
这是我的守卫,我在这里检查用户是否登录并调用 signinRedirect()
:
export class AuthGuardService implements CanActivate {
constructor(
private authService: AuthService
) { }
canActivate() {
const isLoggedIn = this.authService.isLoggedInObs();
isLoggedIn.subscribe(loggedin => {
if (!loggedin) {
this.authService.startSigninMainWindow();
}
});
return isLoggedIn;
}
}
这是 AuthService
class 所有关于 oidc-client 的逻辑所在。
export class AuthService {
mgr: UserManager = new UserManager(settings);
userLoadededEvent: EventEmitter<User> = new EventEmitter<User>();
currentUser: User;
loggedIn = false;
authHeaders: Headers;
private accountID: string;
private accountToken: string;
private internInfoSubject = new BehaviorSubject<InternUser>(null);
public readonly internInfo$ = this.internInfoSubject
.asObservable()
.pipe(
filter(user => user !== null),
distinctUntilChanged()
);
constructor(
private router: Router,
private internPortalService: InternPortalService,
private apiService: ApiService,
private http: HttpClient
) {
this.mgr.events.addUserSignedOut(() => {
this.startSigninMainWindow({ external_logout: true })
})
}
getUser() {
this.mgr
.getUser()
.then(user => {
console.log('got user', user);
this.currentUser = user;
this.userLoadededEvent.emit(user);
})
.catch(function(err) {
console.log(err);
});
}
startSigninMainWindow(query = {}) {
this.mgr.signinRedirect({extraQueryParams: query});
}
endSigninMainWindow() {
this.mgr
.signinRedirectCallback()
.then(user => {
console.log('signed in', user);
this.currentUser = user;
this.setLocalStorage();
})
.catch(function(err) {
console.log(err);
});
}
endSigninSilentMainWindow() {
this.mgr
.signinSilentCallback()
.then(() => {
console.log('end silent signed in');
})
.catch(function(err) {
console.log(err);
});
}
changePassword(): Observable<any> {
const params = new HttpParams()
.set('userId', this.currentUser.profile.sub)
.set('passwordAction', '2')
.set('redirectUrl', window.location.href);
return this.apiService.getIdentityServer('/Token', params);
}
startSignoutMainWindow() {
this.mgr
.signoutRedirect()
.then(function(resp) {
console.log('signed out', resp);
// setTimeout(5000, () => {
// console.log('testing to see if fired...');
// });
})
.catch(function(err) {
console.log(err);
});
}
isLoggedInObs(): Observable<boolean> {
return observableFrom(this.mgr.getUser()).pipe(
map<User, boolean>(user => {
if (user) {
if (!this.internPortalService.getAccountId()) {
this.currentUser = user;
this.setLocalStorage();
}
return true;
} else {
return false;
}
})
);
}
onSignOut(callback: Function){
this.mgr.events.addUserSignedOut(resp => {
console.log("user signed out");
callback();
});
}
get authenticationInfo(): InternUser {
return this.internInfoSubject.value;
}
private setLocalStorage() {
this.accountID = this.currentUser.profile.account_id;
this.accountToken = this.currentUser.access_token;
this.internPortalService.setAccountId(this.accountID, this.accountToken);
this.internPortalService
.getIntern()
.subscribe(res => this.updateToken(res));
}
updateToken(internUser: any): void {
console.log(internUser);
if (!internUser) {
return;
}
// TODO: Refactor once BE migration is completed
internUser.auth = this.currentUser;
internUser.state_locales = this.internPortalService.getStateLocales(
internUser.state
);
this.internInfoSubject.next(internUser);
this.router.navigate(['/intern-portal']);
}
// TODO: To be removed after QA
public updateLocale(counter: number): void {
const stateList = ['TX', 'MI', 'AZ', 'NC', 'SC', 'FL', 'NV', 'IN'];
const newUser = this.authenticationInfo;
newUser.state = stateList[counter];
newUser.state_locales = this.internPortalService.getStateLocales(
newUser.state
);
console.log(`An user from: ${newUser.state_locales.state} was loaded`);
this.internInfoSubject.next(newUser);
}
logout(): void {
localStorage.clear();
this.internInfoSubject.next(null);
}
}
和 signin-oidc-silent
组件:
export class SigninOidcComponent implements OnInit {
private element: any;
constructor(private authService: AuthService) {
}
ngOnInit() {
console.log('init oidc logic');
this.authService.endSigninMainWindow();
}
}
我只是不知道为什么托管应用程序会出现无限循环。实际上,如果我在本地使用客户端并指向我托管的 IDP,我会得到相同的无限循环。
我在控制台上没有看到任何错误,只有这个警告 ResponseValidator._processSigninParams: Response was error login_required
这里是一些 IDP 日志:
2019-04-15 11:16:49.383 +00:00 [DBG] Request path /connect/authorize matched to endpoint type Authorize
2019-04-15 11:16:49.418 +00:00 [DBG] Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint
2019-04-15 11:16:49.419 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
2019-04-15 11:16:49.423 +00:00 [DBG] Start authorize request
2019-04-15 11:16:49.435 +00:00 [DBG] User in authorize request: cfd7214d-305d-4d91-9d50-671dac6b37d8
2019-04-15 11:16:49.436 +00:00 [DBG] Start authorize request protocol validation
2019-04-15 11:16:49.566 +00:00 [DBG] js found in database: true
2019-04-15 11:16:49.569 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:49.624 +00:00 [DBG] Found ["openid","profile","salesforce"] identity scopes in database
2019-04-15 11:16:49.673 +00:00 [DBG] Found ["api1"] API scopes in database
2019-04-15 11:16:49.687 +00:00 [DBG] Found ["openid","profile","salesforce"] identity scopes in database
2019-04-15 11:16:49.703 +00:00 [DBG] Found ["api1"] API scopes in database
2019-04-15 11:16:49.712 +00:00 [DBG] Calling into custom validator: IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator
2019-04-15 11:16:49.755 +00:00 [INF] ValidatedAuthorizeRequest
{"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","ResponseType":"id_token token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid profile salesforce api1","State":"42a8d9eda2a94c61a4f8ac2f13bbee52","UiLocales":null,"Nonce":"76c3d45a35524c908b1593454305a796","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":null,"MaxAge":null,"LoginHint":null,"SessionId":"a593b46f1553fa4d5beae979ec6475ba","Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","response_type":"id_token token","scope":"openid profile salesforce api1","state":"42a8d9eda2a94c61a4f8ac2f13bbee52","nonce":"76c3d45a35524c908b1593454305a796","external_logout":"true"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:49.758 +00:00 [DBG] Client is configured to not require consent, no consent is required
2019-04-15 11:16:49.759 +00:00 [DBG] Creating Implicit Flow response.
2019-04-15 11:16:49.760 +00:00 [DBG] Getting claims for access token for client: js
2019-04-15 11:16:49.765 +00:00 [DBG] Getting claims for access token for subject: cfd7214d-305d-4d91-9d50-671dac6b37d8
2019-04-15 11:16:49.769 +00:00 [DBG] Claim types from profile service that were filtered: ["sub","idp","amr","auth_time"]
2019-04-15 11:16:49.812 +00:00 [DBG] Getting claims for identity token for subject: cfd7214d-305d-4d91-9d50-671dac6b37d8 and client: js
2019-04-15 11:16:49.814 +00:00 [DBG] In addition to an id_token, an access_token was requested. No claims other than sub are included in the id_token. To obtain more user claims, either use the user info endpoint or set AlwaysIncludeUserClaimsInIdToken on the client configuration.
2019-04-15 11:16:49.835 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","Endpoint":"Authorize","SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","Scopes":"openid profile salesforce api1","GrantType":"implicit","Tokens":[{"TokenType":"id_token","TokenValue":"****UIMg","$type":"Token"},{"TokenType":"access_token","TokenValue":"****NWSw","$type":"Token"}],"Category":"Token","Name":"Token Issued Success","EventType":"Success","Id":2000,"Message":null,"ActivityId":"0HLLVFNQC24O5:00000001","TimeStamp":"2019-04-15T11:16:49.0000000Z","ProcessId":11056,"LocalIpAddress":"127.0.0.1:28158","RemoteIpAddress":"167.57.108.74","$type":"TokenIssuedSuccessEvent"}
2019-04-15 11:16:49.845 +00:00 [INF] Authorize endpoint response
{"SubjectId":"cfd7214d-305d-4d91-9d50-671dac6b37d8","ClientId":"js","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc","State":"42a8d9eda2a94c61a4f8ac2f13bbee52","Scope":"openid profile salesforce api1","Error":null,"ErrorDescription":null,"$type":"AuthorizeResponseLog"}
2019-04-15 11:16:56.059 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.067 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.069 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.071 +00:00 [DBG] Request path /.well-known/openid-configuration matched to endpoint type Discovery
2019-04-15 11:16:56.076 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
2019-04-15 11:16:56.077 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
2019-04-15 11:16:56.079 +00:00 [DBG] Start discovery request
2019-04-15 11:16:56.118 +00:00 [DBG] Found ["openid","profile","salesforce","role","api1"] as all scopes in database
2019-04-15 11:16:56.341 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.347 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.349 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.350 +00:00 [DBG] Request path /.well-known/openid-configuration matched to endpoint type Discovery
2019-04-15 11:16:56.351 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint
2019-04-15 11:16:56.352 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration
2019-04-15 11:16:56.353 +00:00 [DBG] Start discovery request
2019-04-15 11:16:56.374 +00:00 [DBG] Found ["openid","profile","salesforce","role","api1"] as all scopes in database
2019-04-15 11:16:56.381 +00:00 [DBG] Request path /connect/checksession matched to endpoint type Checksession
2019-04-15 11:16:56.389 +00:00 [DBG] Endpoint enabled: Checksession, successfully created handler: IdentityServer4.Endpoints.CheckSessionEndpoint
2019-04-15 11:16:56.390 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.CheckSessionEndpoint for /connect/checksession
2019-04-15 11:16:56.392 +00:00 [DBG] Rendering check session result
2019-04-15 11:16:56.613 +00:00 [DBG] CORS request made for path: /.well-known/openid-configuration/jwks from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.618 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:56.621 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:56.622 +00:00 [DBG] Request path /.well-known/openid-configuration/jwks matched to endpoint type Discovery
2019-04-15 11:16:56.624 +00:00 [DBG] Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryKeyEndpoint
2019-04-15 11:16:56.625 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryKeyEndpoint for /.well-known/openid-configuration/jwks
2019-04-15 11:16:56.628 +00:00 [DBG] Start key discovery request
2019-04-15 11:16:56.719 +00:00 [DBG] Request path /connect/authorize matched to endpoint type Authorize
2019-04-15 11:16:56.722 +00:00 [DBG] Endpoint enabled: Authorize, successfully created handler: IdentityServer4.Endpoints.AuthorizeEndpoint
2019-04-15 11:16:56.723 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
2019-04-15 11:16:56.725 +00:00 [DBG] Start authorize request
2019-04-15 11:16:56.726 +00:00 [DBG] No user present in authorize request
2019-04-15 11:16:56.727 +00:00 [DBG] Start authorize request protocol validation
2019-04-15 11:16:56.743 +00:00 [DBG] js found in database: true
2019-04-15 11:16:56.748 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:56.757 +00:00 [DBG] Found ["openid"] identity scopes in database
2019-04-15 11:16:56.760 +00:00 [DBG] Found [] API scopes in database
2019-04-15 11:16:56.767 +00:00 [DBG] Found ["openid"] identity scopes in database
2019-04-15 11:16:56.772 +00:00 [DBG] Found [] API scopes in database
2019-04-15 11:16:56.773 +00:00 [DBG] Calling into custom validator: IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator
2019-04-15 11:16:56.775 +00:00 [INF] ValidatedAuthorizeRequest
{"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"anonymous","ResponseType":"id_token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid","State":"170ef6a2eda34bc6a7c0a5d79fc25a7a","UiLocales":null,"Nonce":"1f0b1599850a4c6882f9e69ceda252ee","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":"none","MaxAge":null,"LoginHint":null,"SessionId":null,"Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","response_type":"id_token","scope":"openid","state":"170ef6a2eda34bc6a7c0a5d79fc25a7a","nonce":"1f0b1599850a4c6882f9e69ceda252ee","prompt":"none"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:56.776 +00:00 [INF] Showing error: prompt=none was requested but user is not authenticated
2019-04-15 11:16:56.778 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","AllowedRedirectUris":["http://localhost:5003/callback.html","http://localhost:5003/signin-oidc","http://localhost:4200/signin-oidc","http://localhost:4200/signin-oidc-silent","https://tt-prince-internportal.azurewebsites.net/signin-oidc","https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc","https://tt-prince-ip-fe-appservice-qa.azurewebsites.net/signin-oidc-silent"],"SubjectId":"anonymous","ResponseType":"id_token","ResponseMode":"fragment","GrantType":"implicit","RequestedScopes":"openid","State":"170ef6a2eda34bc6a7c0a5d79fc25a7a","UiLocales":null,"Nonce":"1f0b1599850a4c6882f9e69ceda252ee","AuthenticationContextReferenceClasses":null,"DisplayMode":null,"PromptMode":"none","MaxAge":null,"LoginHint":null,"SessionId":null,"Raw":{"client_id":"js","redirect_uri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","response_type":"id_token","scope":"openid","state":"170ef6a2eda34bc6a7c0a5d79fc25a7a","nonce":"1f0b1599850a4c6882f9e69ceda252ee","prompt":"none"},"$type":"AuthorizeRequestValidationLog"}
2019-04-15 11:16:56.779 +00:00 [INF] {"ClientId":"js","ClientName":"JavaScript Client","RedirectUri":"https://tt-prince-internportal.azurewebsites.net/signin-oidc-silent","Endpoint":"Authorize","SubjectId":null,"Scopes":"openid","GrantType":"implicit","Error":"login_required","ErrorDescription":null,"Category":"Token","Name":"Token Issued Failure","EventType":"Failure","Id":2001,"Message":null,"ActivityId":"0HLLVFNQC24O6:00000002","TimeStamp":"2019-04-15T11:16:56.0000000Z","ProcessId":11056,"LocalIpAddress":"127.0.0.1:28158","RemoteIpAddress":"167.57.108.74","$type":"TokenIssuedFailureEvent"}
2019-04-15 11:16:57.174 +00:00 [DBG] CORS request made for path: /connect/userinfo from origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:57.178 +00:00 [DBG] Origin https://tt-prince-internportal.azurewebsites.net is allowed: true
2019-04-15 11:16:57.179 +00:00 [DBG] CorsPolicyService allowed origin: https://tt-prince-internportal.azurewebsites.net
2019-04-15 11:16:57.180 +00:00 [DBG] Request path /connect/userinfo matched to endpoint type Userinfo
2019-04-15 11:16:57.185 +00:00 [DBG] Endpoint enabled: Userinfo, successfully created handler: IdentityServer4.Endpoints.UserInfoEndpoint
2019-04-15 11:16:57.186 +00:00 [INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.UserInfoEndpoint for /connect/userinfo
2019-04-15 11:16:57.188 +00:00 [DBG] Start userinfo request
2019-04-15 11:16:57.189 +00:00 [DBG] Bearer token found in header
2019-04-15 11:16:57.240 +00:00 [DBG] js found in database: true
2019-04-15 11:16:57.241 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:57.269 +00:00 [DBG] js found in database: true
2019-04-15 11:16:57.270 +00:00 [DBG] client configuration validation for client js succeeded.
2019-04-15 11:16:57.281 +00:00 [DBG] Calling into custom token validator: IdentityServer4.Validation.DefaultCustomTokenValidator
2019-04-15 11:16:57.283 +00:00 [DBG] Token validation success
我终于找到了为 cookie 设置 SameSite.None
的位置,以便浏览器在检查会话状态时将其发送回 IS。在我的例子中,我使用 ASP.NET Core Identity
所以代码是:
builder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.IsEssential = true;
// we need to disable to allow iframe for authorize requests
options.Cookie.SameSite = AspNetCore.Http.SameSiteMode.None;
});
之后:
var builder = services.AddIdentityServer(options =>
...