7

아이덴티티 서버가 제대로 작동하고 잘 작동합니다. Google 로그인이 작동하고 이메일을 포함한 여러 가지 소유권을 반환합니다.Identity Server 3 페이 스북 로그인 이메일을 받으십시오

페이스 북 로그인이 작동하고, 내 응용 프로그램은 라이브이며, 문제는 내가 OAuth는 엔드 포인트에서 다시 이메일을 얻을 수없는 내가 할 수 없습니다.

에 새로운 사용자가 로그인 할 때 이메일 권한을 요청 사용자 정보를 수동으로 요청하기 위해 access_token을 찾는 것 같습니다. 내가 가지고있는 것은 페이스 북 로그인 엔드 포인트에서 리턴 된 "코드"입니다.

다음은 IdentityServer 설정입니다.

var fb = new FacebookAuthenticationOptions 
      { 
       AuthenticationType = "Facebook", 
       SignInAsAuthenticationType = signInAsType, 
       AppId = ConfigurationManager.AppSettings["Facebook:AppId"], 
       AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"] 
      }; 

      fb.Scope.Add("email"); 

      app.UseFacebookAuthentication(fb); 

그런 다음 물론 나는 AuthenticateLocalAsync 방법을 사용자 정의했지만, 난 단지 받고있어 주장은 이름이 포함됩니다. 이메일 요구 없음.

신원 확인 서버의 소스 코드를 파헤 치면서 페이스 북의 주장을 변형시키는 일이 발생했다는 것을 깨달았습니다. 따라서이 클래스를 디버깅하고 클레임을 제거하는지 확인합니다.

나는 또한 http 호출을 피 들러로 보았고, 다음과 같은 것을 보았다. (코드 형식이 URL에서 잘 작동하지 않는다는 사과 만한다.) querystring params를 자신의 줄 하나에 포맷하려했으나)

  1. (facebook.com)

    /대화/OAuth를 ? = RESPONSE_TYPE 코드 CLIENT_ID = & & XXX 를 redirect_uri = HTTPS % 3A % 2F % 2Fidentity. 사이트] .COM % 2Fid % 2Fsignin-facebook & 범위 = & 이메일 상태 = XXX

  2. (facebook.com)

    /login.php ? skip_api_login = 1 API_KEY = & & XXX signed_next = 1 다음 = & HTTPS % 3A % 2F % 2Fwww.facebook.com % 2Fv2.7 % 2Fdialog % 2Foauth % 3Fredirect_uri % 3Dhttps % 253A % 252F % 252Fidentity. [site] .com % 252Fid % 252Fsignin-facebook % 26state % 3Dxxx % 26scope % 3Demail % 26response_type % 3Dcode % 26client_id % 3Dxxx % 26ret % 3Dlogin % 26logger_id % 3Dxxx & cancel_url = https % 3A % 2F % 2 신원. [site]. COM % 2Fid % 2Fsignin - 한국어 % 3Ferror % 3Daccess_denied % 26error_code % 3D200 % 26error_description % 3DPermissions % 2Berror % 26error_reason % 3Duser_denied % 26state % 3Dxxx % 23_ % 3D_ & 디스플레이 = 페이지 & 로케일 = ko 페이지 & logger_id = XXX

  3. (facebook.com)

    POST/쿠키/동의 /? PV = 1 & 조선 민주주의 인민 공화국 = 1 HTTP/1.1

  4. (facebook.com)

    /login.php ? login_attempt = 1 다음 = https % 3A % 2F % 2Fwww.facebook.com % 2Fv2.7 % 2Fdialog % 2Foauth % 3Fredirect_uri % 3Dhttps % 253A % 252F % 252 [사이트].COM % 252Fid % 252Fsignin - 한국어 26state % % % 3Dxxx 26scope % 3Demail % 26response_type % 3Dcode % 26client_id % 3Dxxx % 26ret % 3Dlogin % 26logger_id % 3Dxxx & LWV = 100

  5. (facebook.com)

    /v2.7/dialog/oauth ? = redirect_uri로 HTTPS % 3A % 2F % 2Fidentity. 사이트] .COM % 2Fid % 2Fsignin - 한국어 상태 = & & XXX 범위 = 이메일 RESPONSE_TYPE = & & 코드 CLIENT_ID = xxx & ret = login 01 23,516,& logger_id = XXX & 해시 = XXX

  6. (신원 서버)

    /아이디/로그인의-페이스 북 ? 코드 = XXX & 상태 = XXX

나는 코드를 보았다 매개 변수를 마지막 호출 및 어쩌면 내가 페이스 북 API에서 access_token 얻을 코드를 사용할 수 있다고 생각 https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow

그러나 코드를 이미 사용했다는 메시지를 API에서 받았습니다.

또한 UserInformationEndpoint를 FacebookAuthenticationOptions으로 변경하여 기본 엔드 포인트 위치의 끝에? fields = email을 추가하여 전자 메일을 요청하도록했지만 ID 서버가 오류를 발생시킵니다. "There was were 외부 공급자에 로그인하는 중 오류가 발생했습니다. 오류 메시지는 : access_denied "입니다.

response_type = id_token으로 요청을 보내도록 미들웨어를 변경할 수 있지만이 방법을 알아낼 수 없거나 해당 액세스 토큰을 추출하는 방법을 알 수 없다면이 문제를 모두 해결할 수 있습니다. Facebook C# SDK를 사용할 수있는 첫 번째 장소.

그래서 어떤 도움이나 방향이 굉장 할 것입니다. 나는 연구하고 문제를 해결하려고 무수한 시간을 보냈다. 내가해야 할 일은 IdentityServer3를 통해 로그인 한 사용자의 전자 메일 주소를 얻는 것뿐입니다. 너무 열심히 들리지만 아직 붙어 있습니다.

+0

인증 코드를 사용하여 "프로필"범위를 가져올 수 있습니까? 그러면 사용자와 그의 속성에 대한 정보를 얻을 수 있습니다. 요청한 범위는 무엇입니까? 이것이 인증 코드 흐름 인 경우 해당 범위는 인증 코드를 요청하는 부분이어야합니다. –

+0

안녕하세요, Mitra, 귀하의 제안에 감사드립니다. 나는 실제로 이미 성공을 시도했다. "프로필"범위를 추가하려고하면이 메시지가 다시 나타납니다. 외부 공급자에 로그인하는 중 오류가 발생했습니다. 오류 메시지는 다음과 같습니다 : access_denied. 어떤 제안? – Ryan

+1

또 다른 방법은 Id_token에서 정보를 추출하는 것입니다. 아마도 auth_code로 토큰을 요청할 때 얻은 http 응답에서 id_token을 가져올 수 있어야합니다. –

답변

3

나는 이것을 알아 냈습니다. 대답은 Mitra의 의견과 관련이 있습니다. 그 답변 중 어느 것도 응답을받지 못했기 때문에 여기에 다른 답변을 추가하고 있습니다. 먼저 Facebook의 인증 엔드 포인트에서 코드 (인증 코드)가 아닌 access_token을 요청해야합니다. 이를 위해 (읽기 기능을 제공합니다) 나는 무시됩니다 IdentityServer3 Samples Repository에서 다음 file을 사용하고 있습니다.이 로그인 된 후에는 당신이 응답을 잡을 필요가있다, 그 다음이

 var fb = new FacebookAuthenticationOptions 
     { 
      AuthenticationType = "Facebook", 
      SignInAsAuthenticationType = signInAsType, 
      AppId = ConfigurationManager.AppSettings["Facebook:AppId"], 
      AppSecret = ConfigurationManager.AppSettings["Facebook:AppSecret"], 
      Provider = new FacebookAuthenticationProvider() 
      { 
       OnAuthenticated = (context) => 
       { 
        context.Identity.AddClaim(new System.Security.Claims.Claim("urn:facebook:access_token", context.AccessToken, ClaimValueTypes.String, "Facebook")); 
        return Task.FromResult(0); 
       } 
      } 

     }; 

     fb.Scope.Add("email"); 

     app.UseFacebookAuthentication(fb); 

처럼를 설정하기위한 외부 사이트에서 사용자를 로그인하는 데 필요한 메소드 이 응답에서 ExternalAuthenticationContext에서 새로 반환 된 access_token 클레임과 함께 C# Facebook SDK을 사용하여 필요한 필드를 요청하고이를 클레임 목록에 추가합니다. 그런 다음 해당 정보를 사용하여 사용자를 만들거나 로그인 할 수 있습니다.

public override async Task AuthenticateExternalAsync(ExternalAuthenticationContext ctx) 
    { 
     var externalUser = ctx.ExternalIdentity; 
     var claimsList = ctx.ExternalIdentity.Claims.ToList(); 
     if (externalUser.Provider == "Facebook") 
     { 
      var extraClaims = GetAdditionalFacebookClaims(externalUser.Claims.First(claim => claim.Type == "urn:facebook:access_token")); 
      claimsList.Add(new Claim("email", extraClaims.First(k => k.Key == "email").Value.ToString())); 
      claimsList.Add(new Claim("given_name", extraClaims.First(k => k.Key == "first_name").Value.ToString())); 
      claimsList.Add(new Claim("family_name", extraClaims.First(k => k.Key == "last_name").Value.ToString())); 
     } 

     if (externalUser == null) 
     { 
      throw new ArgumentNullException("externalUser"); 
     } 

     var user = await userManager.FindAsync(new Microsoft.AspNet.Identity.UserLoginInfo(externalUser.Provider, externalUser.ProviderId)); 
     if (user == null) 
     { 
      ctx.AuthenticateResult = await ProcessNewExternalAccountAsync(externalUser.Provider, externalUser.ProviderId, claimsList); 
     } 
     else 
     { 
      ctx.AuthenticateResult = await ProcessExistingExternalAccountAsync(user.Id, externalUser.Provider, externalUser.ProviderId, claimsList); 
     } 
    } 

그리고 그게 전부입니다! 이 프로세스를 단순화하기위한 제안 사항이 있으면 알려주십시오.FacebookAuthenticationOptions에서 API 호출을 수행하기 위해이 코드를 수정하려고했지만 이벤트 속성이 더 이상 존재하지 않게되었습니다.

편집 : GetAdditionalFacebookClaims 메서드는 단순히 액세스 토큰이있는 액세스 토큰이있는 경우 새 FacebookClient를 만드는 메서드이며 필요한 다른 사용자 클래임을 위해 Facebook API를 쿼리합니다. 예를 들어 내 방식은 다음과 같습니다.

protected static JsonObject GetAdditionalFacebookClaims(Claim accessToken) 
    { 
     var fb = new FacebookClient(accessToken.Value); 
     return fb.Get("me", new {fields = new[] {"email", "first_name", "last_name"}}) as JsonObject; 
    } 
+0

확실히 올바른 방향으로 나를 향하고있는 것 같습니다. 그러나 GetAdditionalFacebookClaims 메서드가 어디에 있는지 알 수 없습니다. –

+0

@Chris_ 누락 된 방법을 제공하기 위해 답을 업데이트했습니다. – Ryan

+3

'FacebookAuthenticationProvider.OnAuthenticated' 내에 페이스 북에서 이메일을받는 논리를 넣으면,'AuthenticateExternalAsync()'안에 특별한 경우 로직이 필요 없다. –

관련 문제