0

我正在創建一個訪問我的服務的移動應用程序(Xamarin + MvvmCross)Web API 2 + Owin並試圖支持外部登錄。對於以下內容,假設我已經註冊了外部身份驗證用戶,並且只想從移動應用登錄用戶。使用ASP.NET WebApi 2移動應用程序的Microsoft Graph外部身份驗證

目前我的Facebook登錄工作主要是在這個ASP.NET Web API 2 external logins with Facebook and Google in AngularJS app之後工作的,但是在幾個小時後,我無法弄清楚如何實現微軟登錄的相同策略,因爲我找不到驗證Microsoft訪問令牌的方法。

我的理解是,爲了叫我自己的API(如讓我的用戶數據和對象),我需要先執行以下操作,從我自己的服務交換外部訪問令牌本地訪問令牌:

  1. 身份驗證與外部供應商(移動應用)
  2. 發送提供商訪問令牌到我的服務器(網頁API 2)
  3. 驗證與供應商的訪問令牌來確定用戶是否是合法的 - 在這個過程中接收ProviderKey(Facebook中的userId和g oogle)
  4. 登錄本地使用提供程序名稱用戶ID從第3步
  5. 用戶生成在當前登錄用戶的本地訪問令牌。

Facebook目前通過上面列出的網絡和移動應用程序的整個過程。但是,通過Microsoft,我可以在移動應用程序上進行身份驗證,然後獲得Microsoft訪問令牌,但我堅持在步驟3中驗證服務器上的訪問令牌,以接收我可用於識別我的應用中已註冊的用戶的任何有用信息。

爲了識別正確的用戶,我需要AspNetUserLogins表中的登錄提供程序和ProviderKey

收到Microsoft Access令牌後,如何驗證令牌並檢查匹配的提供者名稱和提供者密鑰?

這是外部認證的通用/標準方法嗎?如果是這樣的話,我認爲會有更多的信息。所有和任何幫助非常感謝。

額外的資訊

我也在努力,以支持正常的Microsoft帳戶以及使用新的Microsoft Graph API(統一office365)工作/學校賬戶。因此,根據微軟/組織帳戶的不同,看起來有不同的提供者密鑰。https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/v2.0

代碼示例

第3步 - 驗證外部訪問令牌來獲取用戶的登錄信息

Private async Task<ParsedExternalAccessToken> VerifyExternalAccessToken(string provider, string accessToken) { 
      ParsedExternalAccessToken parsedToken = null; 

      var verifyTokenEndPoint = ""; 

      if (provider == Resources.Constants.FacebookProvider) { 
       //You can get it from here: https://developers.facebook.com/tools/accesstoken/ 
       //More about debug_tokn here: https://stackoverflow.com/questions/16641083/how-does-one-get-the-app-access-token-for-debug-token-inspection-on-facebook 

       var appToken = WebConfigurationManager.AppSettings["fb_app_token"]; 
       verifyTokenEndPoint = string.Format("https://graph.facebook.com/debug_token?input_token={0}&access_token={1}", accessToken, appToken); 
      } else if (provider == Resources.Constants.GoogleProvider) { 
       verifyTokenEndPoint = string.Format("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={0}", accessToken); 
      } else if (provider == "Microsoft" || provider == Resources.Constants.MicrosoftAccountProvider || provider == Resources.Constants.MicrooftSchoolOrWorkAccountProvider) { 
       //made up end point -> what is the real answer/solution? 
       verifyTokenEndPoint = string.Format("https://login.microsoftonline.com/common/v2.0/tokeninfo?access_token={0}", accessToken); 

      } else { 
       return null; 
      } 

      var client = new HttpClient(); 
      var uri = new Uri(verifyTokenEndPoint); 
      var response = await client.GetAsync(uri); 

      if (response.IsSuccessStatusCode) { 
       var content = await response.Content.ReadAsStringAsync(); 

       dynamic jObj = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(content); 

       parsedToken = new ParsedExternalAccessToken(); 

       if (provider == Resources.Constants.FacebookProvider) { 
        parsedToken.user_id = jObj["data"]["user_id"]; 
        parsedToken.app_id = jObj["data"]["app_id"]; 

        if (!string.Equals(Startup.facebookAuthOptions.AppId, parsedToken.app_id, StringComparison.OrdinalIgnoreCase)) { 
         return null; 
        } 
       } else if (provider == Resources.Constants.GoogleProvider) { 
        parsedToken.user_id = jObj["user_id"]; 
        parsedToken.app_id = jObj["audience"]; 

        if (!string.Equals(Startup.googleAuthOptions.ClientId, parsedToken.app_id, StringComparison.OrdinalIgnoreCase)) { 
         return null; 
        } 

       } else if (provider == Resources.Constants.MicrosoftAccountProvider || provider == Resources.Constants.MicrooftSchoolOrWorkAccountProvider) { 
        throw new NotImplementedException("Microsoft Access Token Validation not implemented"); 
       } 

      } 

      return parsedToken; 
     } 

第4步 - 獲取當地訪問令牌

public async Task<IHttpActionResult> ObtainLocalAccessToken(string provider, string externalAccessToken) { 

      if (string.IsNullOrWhiteSpace(provider) || string.IsNullOrWhiteSpace(externalAccessToken)) { 
       return ApiErrorResult(ServiceResults.ExternalAuth.Codes.ProviderOrExternalAccessTokenIsNotSent, ServiceResults.ExternalAuth.Messages.ProviderOrExternalAccessTokenIsNotSent); 
      } 

      var verifiedAccessToken = await VerifyExternalAccessToken(provider, externalAccessToken); 
      if (verifiedAccessToken == null) { 
       return ApiErrorResult(ServiceResults.ExternalAuth.Codes.InvalidProviderOrExternalAccessToken, ServiceResults.ExternalAuth.Messages.InvalidProviderOrExternalAccessToken); 
      } 

      var user = await _userManager.FindAsync(new UserLoginInfo(provider, verifiedAccessToken.user_id)); 

      bool hasRegistered = user != null; 

      if (!hasRegistered) { 
       return ApiErrorResult(ServiceResults.ExternalAuth.Codes.ExternalUserIsNotRegistered, ServiceResults.ExternalAuth.Messages.ExternalUserIsNotRegistered); 
      } 

      //generate access token response 
      var accessTokenResponse = await GenerateLocalOauthToken(user); 

      return Ok(accessTokenResponse); 

     } 

謝謝

UPDATE

我試着實現了@dstrockis選項,但成功有限。在這兩種選擇,我仍然無法找出該用什麼來匹配到ProviderKey

使得圖形API調用當得到用戶的,不匹配的值存儲在ProviderKey,比如在Facebook中使用的帳戶及谷歌。 Microsoft ProviderKey值看起來像:AAAAAAAAAAAAAAAAAAAAADWmHuzvvAQpO ******* 9PM。

我還設法按照建議使用JWT驗證庫驗證訪問令牌。查看索賠,我現在可以確定正確的LoginProvider(好的開始),但是我仍然無法找到任何與ProviderKey中存儲的值相匹配的值。

此值必須與用戶有關,但不直接與任何內容匹配。有誰知道ProviderKey來自OpenIdAuthentication for Microsoft的何處。它是否從另一個值加密?

驗證令牌JWT

private async Task ValidateMicrosoftToken(string token) { 
      string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration"; 
      ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint); 
      OpenIdConnectConfiguration config = await configManager.GetConfigurationAsync(); 

      TokenValidationParameters validationParameters = new TokenValidationParameters { 
       ValidateAudience = false, 
       ValidateIssuer = false, 
       IssuerSigningTokens = config.SigningTokens, 
       ValidateLifetime = false 
      }; 

      JwtSecurityTokenHandler tokendHandler = new JwtSecurityTokenHandler(); 

      SecurityToken jwt; 

      var result = tokendHandler.ValidateToken(token, validationParameters, out jwt); 

      //result contains claims with lots of values 
      //get provider key from claims???? 
     } 

驗證提供者 - Startup.Auth

microsoftAccountAuthOptions = new OpenIdConnectAuthenticationOptions() { 
       Description = new AuthenticationDescription() { AuthenticationType = "OpenIdConnect", Caption = "Microsoft"}, 
       AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive, 
       ClientId = appId, 
       Authority = authority, 
       Scope = "openid user.read email " + string.Join(" ", scopes), 
       RedirectUri = redirectUri, 
       //PostLogoutRedirectUri = "/", 
       TokenValidationParameters = new TokenValidationParameters { 
        //..... 
       }, 
       Notifications = new OpenIdConnectAuthenticationNotifications { 
        //..... 
       } 
      }; 
      app.UseOpenIdConnectAuthentication(microsoftAccountAuthOptions); 

回答

0

這種做法是完全正常的。對於第3步,您確實有兩種選擇:

祝你好運!

相關問題