2017-04-20 7 views
1

첫 번째 문제는 이것이 큰 게시물이지만 몇 주 동안이 문제를 추적하고 있으며 문제의 원인이 될 수있는 많은 정보를 수집합니다.Asp.NET Core OpenIddict invalid_grant

OpenIddict 인증과 함께 Angular2 응용 프로그램을 사용하고 있습니다. 클라이언트 응용 프로그램에서 access_token, refresh_token을 얻습니다. refresh_token을 사용하여 새로운 access_token을 얻을 수 있습니다. 모든 것이 작동합니다. 거의.

POST https://mydomain:2000/api/authorization/token 400 (잘못된 요청)

및 응답 :

error:"invalid_grant" 
error_description:"Invalid ticket" 

내가 트리플 확인 모든과 refresh_token도 어떤 점에서

나는 서버에서 오류 응답을 얻을 나는 옳다. 디자인에 대해

:
내가 만료 access_token이 있다면 확인 서버에 요청을하기 전에. 만료되면 refresh_token으로 새로운 access_token을 요청합니다.

그리고 임의의 시간에 작동하지만 임의의 시간 (반복) refresh_token이 유효하지 않게됩니다.
AddEphemeralSigningKey과 관련이 있지만 AddSigningCertificate으로 변경합니다. (세부 사항은 this 스레드입니다.)

제가 생각하기에, IIS는 일정한 활동 시간 후에 Kestrel을 죽입니다. 내 응용 프로그램 풀 설정은 다음과 같습니다

StartMode: OnDemand 
Idle Time-out (minutes): 20 
Idle Time-out (action): Terminate 

나는 새로운 요청이 후, OpenIddict 잘못 것을 해제 토굴 refresh_token도 의심, 황조롱이가 다시 시작했기 때문에? 또는 나는 틀린가?

또한 OpenIddict 테이블과 OpenIddictApplications, OpenIddictAuthorizations 및 OpenIddictScopes가 모두 비어 있는지 확인합니다. 만 OpenIddictTokens 일부 데이터를 포함 (및 모든 유형 refresh_token도이다) :

OpenIddictTokens

내가 기대, refresh_tokens 어딘가에 저장됩니다. 어디서? 어쩌면 이것이 소스 문제 일 수 있습니다. 왜 내가 임의의 시간 (아마도 Kestrel이 재시작 될 때) 이후에 내 refresh_tokens가 유효하지 않은 것입니까?

IIS 로그 : 여기

Hosting environment: Production 
Content root path: D:\Podatki\OpPISWeb\WWWProduction 
Now listening on: http://localhost:1408 
Application started. Press Ctrl+C to shut down. 
fail: AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerMiddleware[0] 
     The token request was rejected because the authorization code or the refresh token was invalid. 
fail: AspNet.Security.OpenIdConnect.Server.OpenIdConnectServerMiddleware[0] 
     The token request was rejected because the authorization code or the refresh token was invalid. 

내 시작입니다.CS :

public void ConfigureServices(IServiceCollection services) 
{ 
    try 
    { 
     services.Configure<IISOptions>(options => 
     { 
     }); 

     services.AddMvc(); 
     services.AddMvcCore().AddDataAnnotations(); 

     services.AddEntityFrameworkSqlServer(); 

     services.AddScoped<UserStore<AppUser, AppRole, AppDbContext, int, AppUserClaim, AppUserRole, AppUserLogin, AppUserToken, AppRoleClaim>, AppUserStore>(); 
     services.AddScoped<UserManager<AppUser>, AppUserManager>(); 
     services.AddScoped<RoleManager<AppRole>, AppRoleManager>(); 
     services.AddScoped<SignInManager<AppUser>, AppSignInManager>(); 
     services.AddScoped<RoleStore<AppRole, AppDbContext, int, AppUserRole, AppRoleClaim>, AppRoleStore>(); 

     var connection = Configuration["ConnectionStrings:Web"]; 
     services.AddDbContext<AppDbContext>(options => 
     { 
      options.UseSqlServer(connection); 
      options.UseOpenIddict<int>(); 
      if (this.env.IsDevelopment()) 
       options.EnableSensitiveDataLogging(); 
     }); 


     services 
      .AddIdentity<AppUser, AppRole>() 
      .AddUserStore<AppUserStore>() 
      .AddUserManager<AppUserManager>() 
      .AddRoleStore<AppRoleStore>() 
      .AddRoleManager<AppRoleManager>() 
      .AddSignInManager<AppSignInManager>() 
      .AddDefaultTokenProviders(); 

     services.Configure<IdentityOptions>(options => 
      { 
       options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name; 
       options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject; 
       options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role; 
      }); 

     services.AddOpenIddict<int>(options => 
     { 
      options.AddEntityFrameworkCoreStores<AppDbContext>(); 
      options.AddMvcBinders(); 
      options.EnableTokenEndpoint("/API/authorization/token"); 
      options.AllowPasswordFlow(); 
      options.AllowRefreshTokenFlow(); 
      options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:google_identity_token"); 
      options.AllowCustomFlow("urn:ietf:params:oauth:grant-type:logedin"); 
      options.UseJsonWebTokens(); 
      if (this.env.IsDevelopment()) 
       options.AddEphemeralSigningKey(); 
      else 
       options.AddSigningCertificate(new FileStream(
        Directory.GetCurrentDirectory() + "/Resources/cert.pfx", FileMode.Open), "password"); 
      options.SetAccessTokenLifetime(TimeSpan.FromMinutes(30)); 
      options.SetRefreshTokenLifetime(TimeSpan.FromDays(14)); 
      if (this.env.IsDevelopment()) 
       options.DisableHttpsRequirement(); 
     }); 

     services.AddSingleton<DbSeeder>(); 
     services.AddSingleton<IConfiguration>(c => { return Configuration; }); 

    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.ToString()); 
     throw; 
    } 
} 

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, DbSeeder dbSeeder) 
{ 
    loggerFactory.AddConsole(this.Configuration.GetSection("Logging")); 
    loggerFactory.AddDebug(); 

    if (env.IsDevelopment()) 
    { 
     app.UseDeveloperExceptionPage(); 
     app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions 
     { 
      HotModuleReplacement = true 
     }); 
    } 
    app.UseStaticFiles(); 

    app.UseStaticFiles(new StaticFileOptions() 
    { 
     FileProvider = new PhysicalFileProvider(this.Configuration["Directories:Upload"]), 
     RequestPath = new PathString("/Files") 
    }); 

    app.UseOpenIddict(); 

    var JwtOptions = new JwtBearerOptions() 
    { 
     Authority = this.Configuration["Authentication:OpenIddict:Authority"], 
     Audience = "OpPISWeb", 
     AutomaticAuthenticate = true, 
     AutomaticChallenge = true, 

     RequireHttpsMetadata = false 
    }; 
    JwtOptions.RequireHttpsMetadata = !env.IsDevelopment(); 
    app.UseJwtBearerAuthentication(JwtOptions); 

    app.UseMvc(); 

    using (var context = new AppDbContext(this.Configuration)) 
    { 
     context.Database.Migrate(); 
    } 
    try 
    { 
     dbSeeder.SeedAsync(); 
    } 
    catch (AggregateException e) 
    { 
     throw new Exception(e.ToString()); 
    } 
} 

콘솔 스크린 샷 : 이 Getting refresh_token Sending refresh_token

업데이트 : 결국 내가해야 할 일을했을 모두에서
은 다음과 같습니다

services.AddDataProtection() 
        .SetApplicationName(this.Configuration["Authentication:ApplicationId"]) 
        .PersistKeysToFileSystem(new DirectoryInfo(this.Configuration["Directories:Keys"])); 
권한을 추가하는 것을 잊지 마십시오

디렉터리 용 IIS : Keys 폴더

답변

1

그 refresh_tokens는 어딘가에 저장됩니다. 어디에?

Nowhere. OpenIddict에서 발급 한 인증 코드, 새로 고침 토큰 및 액세스 토큰 (기본 형식을 사용하는 경우)은 이며 자체적 인이며 보안상의 이유로 저장되지 않습니다. 토큰과 연관된 메타 데이터 또는 토큰과 같은 메타 데이터 만 저장됩니다.

ASP.NET 핵심 데이터 보호 스택 OpenIddict가 토큰을 암호화하는 데 사용하는 암호화 키를 올바르게 유지하도록 환경을 구성하지 않았기 때문에 발생하는 문제 일 가능성이 큽니다. 이 문제를 해결하는 방법에 대한 자세한 내용은 OpenIddict: 401 errors when two or more service instance count을 참조하십시오.

+0

@Pinpint : 이것이 사실이라고 생각합니다. 다른 사용자가 로그인하면 문제가 발생합니다. 권장 방법이 있습니까? 나는 당신의 예를 점검하고, 관련 주제를 읽는다. 어쩌면 몇 줄의 코드를 사용해야합니까? 감사합니다. – Makla

관련 문제