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 =>
...