2017-10-23 15 views
0

백엔드 웹 API (코어 2.0)와 통신하는 모바일 앱이 있습니다. 현재 API는 Opendidict with Facebook 통합을 사용하도록 구성되어 있으며 아래 나열된 구성을 기반으로합니다.외부 로그인 관련 Openiddict 안내

public static IServiceCollection AddAuthentication(this IServiceCollection services, AppSettings settings) 
    { 
     services.AddOpenIddict<int>(options => 
     { 
      options.AddEntityFrameworkCoreStores<RouteManagerContext>(); 
      options.AddMvcBinders(); 
      options.EnableAuthorizationEndpoint("/auth/authorize"); 
      options.EnableTokenEndpoint("/auth/token"); 
      options.AllowAuthorizationCodeFlow(); 
      options.AllowImplicitFlow(); 
      options.AllowPasswordFlow(); 
      options.AllowRefreshTokenFlow(); 
      options.SetAccessTokenLifetime(TimeSpan.FromMinutes(1)); 
      options.SetRefreshTokenLifetime(TimeSpan.FromMinutes(20160)); 
      options.DisableHttpsRequirement(); 
      options.AddEphemeralSigningKey(); 
     }); 
     services.AddAuthentication() 
      .AddFacebook(o => { o.ClientId = settings.FacebookAppID; o.ClientSecret = settings.FacebookAppSecret; }) 
      .AddOAuthValidation(); 
     return services; 
    } 

로컬 계정을 사용할 때 비밀번호 흐름이 완벽하게 작동합니다. 내가 고민하고있는 것은 페이스 북을 성공적으로 인증 한 후 액세스/새로 고침 토큰을 반환하는 방법이다. 나는 ExternalLogin과 ExternalLoginCallback을 가진 표준 계정 컨트롤러를 가지고있어, 성공적으로 로그인하여 묶여 있고 로그인 한 로컬 사용자 계정을 얻을 수 있기 때문에 완벽하게 작동합니다.

내 생각에 사용자는 Facebook 로그인을 클릭합니다. ExternalLogincallBack을 호출하여 사용자를 로그인합니다. 그 다음에는 비밀번호 흐름과 마찬가지로 액세스/새로 고침 토큰을 반환하기 만하면됩니다.

ExternalLoginCallback에서 리디렉션 (/ auth/authorize? ...)의 암시 적 흐름 인수를 제공하여 ImplicitFlow를 사용하려고하면 offline_scope를 지정하더라도 액세스 토큰을 얻을 수 있지만 새로 고침 토큰을 얻을 수 없습니다. . 읽은 것에서는 암시 적 플로우가 새로 고침을 지원하지 않으므로 코드 플로우를 시도했습니다.

CodeFlow를 사용할 때 코드 토큰을 "/ auth/authorize"로 리디렉션 할 수 있지만 직접 액세스/새로 고침 토큰을 반환하기 위해 권한 부여 끝점에서 토큰 끝점을 호출하는 방법을 알 수 없습니다 클라이언트 앱에 코드를 클라이언트에 반환하고 토큰 엔드 포인트에 게시하여 토큰 액세스/새로 고치기를 다시 호출해야합니까?

이것은 정확하지 않으며 난처한 상황입니다. 암호 흐름과 같이 외부에서 로그인 한 후 액세스/새로 고침 토큰을 반환 할 수 있어야합니다. 내가 며칠 동안이 일에 어려움을 겪으면서 어떤 도움이라도 대단히 감사 할 것입니다.

[HttpGet("~/auth/authorize")] 
    public async Task<IActionResult> Authorize(OpenIdConnectRequest request) 
    { 
     if (!User.Identity.IsAuthenticated) 
     { 
      // If the client application request promptless authentication, 
      // return an error indicating that the user is not logged in. 
      if (request.HasPrompt(OpenIdConnectConstants.Prompts.None)) 
      { 
       var properties = new AuthenticationProperties(new Dictionary<string, string> 
       { 
        [OpenIdConnectConstants.Properties.Error] = OpenIdConnectConstants.Errors.LoginRequired, 
        [OpenIdConnectConstants.Properties.ErrorDescription] = "The user is not logged in." 
       }); 

       // Ask OpenIddict to return a login_required error to the client application. 
       return Forbid(properties, OpenIdConnectServerDefaults.AuthenticationScheme); 
      } 

      return Challenge(); 
     } 

     // Retrieve the profile of the logged in user. 
     var user = await _userManager.GetUserAsync(User); 
     if (user == null) 
     { 
      return BadRequest(new 
      { 
       Error = OpenIdConnectConstants.Errors.ServerError, 
       ErrorDescription = "An internal error has occurred" 
      }); 
     } 

     // Create a new authentication ticket. 
     var ticket = await CreateTicketAsync(request, user); 

     // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. 
     return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme); 
    } 

    private async Task<AuthenticationTicket> CreateTicketAsync(OpenIdConnectRequest request, ApplicationUser user, AuthenticationProperties properties = null) 
    { 
     // Create a new ClaimsPrincipal containing the claims that will be used to create an id_token, a token or a code. 
     var principal = await _signInManager.CreateUserPrincipalAsync(user); 

     // Create a new authentication ticket holding the user identity. 
     var ticket = new AuthenticationTicket(principal, properties, OpenIdConnectServerDefaults.AuthenticationScheme); 

     if (!request.IsRefreshTokenGrantType()) 
     { 
      // Set the list of scopes granted to the client application. 
      // Note: the offline_access scope must be granted to allow OpenIddict to return a refresh token. 
      ticket.SetScopes(new[] 
      { 
       OpenIdConnectConstants.Scopes.OpenId, 
       OpenIdConnectConstants.Scopes.Email, 
       OpenIdConnectConstants.Scopes.Profile, 
       OpenIdConnectConstants.Scopes.OfflineAccess, 
       OpenIddictConstants.Scopes.Roles 
      }.Intersect(request.GetScopes())); 
     } 
     ticket.SetResources("RouteManagerAPI"); 

     // Note: by default, claims are NOT automatically included in the access and identity tokens. 
     // To allow OpenIddict to serialize them, you must attach them to a destination, that specifies 
     // whether they should be included in access tokens, in identity tokens or in both. 

     foreach (var claim in ticket.Principal.Claims) 
     { 
      // Never include the security stamp in the access and identity tokens, as it's a secret value. 
      if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType) 
      { 
       continue; 
      } 
      var destinations = new List<string> 
      { 
       OpenIdConnectConstants.Destinations.AccessToken 
      }; 
      // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application. 
      // The other claims will only be added to the access_token, which is encrypted when using the default format. 
      if ((claim.Type == OpenIdConnectConstants.Claims.Name && ticket.HasScope(OpenIdConnectConstants.Scopes.Profile)) || 
       (claim.Type == OpenIdConnectConstants.Claims.Email && ticket.HasScope(OpenIdConnectConstants.Scopes.Email)) || 
       (claim.Type == OpenIdConnectConstants.Claims.Role && ticket.HasScope(OpenIddictConstants.Claims.Roles))) 
      { 
       destinations.Add(OpenIdConnectConstants.Destinations.IdentityToken); 
      } 
      claim.SetDestinations(destinations); 
     } 
     return ticket; 
    } 

답변

0

나는 CodeFlow를 사용하려고하면, 내가 토큰 코드를 얻을 수 있지만/액세스를 반환 할 권한 부여 엔드 포인트에서 토큰 엔드 포인트에 호출에 직접 토큰을 갱신하는 방법을 알아낼 수 없습니다 클라이언트 응용 프로그램. 코드를 클라이언트에 반환하고 토큰 엔드 포인트에 게시하여 토큰 액세스/새로 고치기를 다시 호출해야합니까?

코드 흐름이 2 단계 프로세스이므로 정확히 수행해야합니다. 모바일 앱에 인증 코드가 있으면 토큰 엔드 포인트에 대한 간단한 HTTP 호출을 사용하여 코드를 사용해야합니다 액세스 토큰 및 새로 고침 토큰.

+0

확인 ... 확인 만하고 있습니다. 외부 인증을 작동시키는 유일한 방법은 두 단계 프로세스 인 코드 흐름을 사용하는 것입니다. 리프레시 토큰으로 외부 인증을 지원하는 다른 플로우는 없습니다. 옳은? – Geekn

+0

수정. OAuth2/OIDC 스펙은 명시 적으로 인증 엔드 포인트에서 새로 고침 토큰을 반환하지 않으므로 새로 고침 토큰을 다시 가져 오기 위해 코드 또는 하이브리드와 같은 2 단계 플로우를 사용해야하는 이유입니다. – Pinpoint

+0

죄송합니다 ... 마지막 질문입니다. 클라이언트 응용 프로그램은 웹 로그인을 통해 외부 로그인 프로세스를 시작합니다. 코드를 가져올 수 있도록이 웹보기로 필요한 리디렉션을 만드는 방법에 대한 지침이 있습니까? – Geekn