2015-12-03 96 views
9

我正在開發一個項目,其中第三方提供程序將充當基於Oauth2的授權服務器。一個基於Asp.net MVC 5的客戶端將發送用戶到授權服務器進行認證(使用登錄/密碼),auth服務器將返回一個訪問令牌回MVC客戶端。任何進一步的資源服務器(API)調用都將使用訪問令牌。OWIN OpenID連接授權無法授權安全控制器/操作

爲了實現這一點,我使用了Microsoft.Owin.Security.OpenIdConnect和UseOpenIdConnectAuthentication擴展。我能夠成功重定向並從auth服務器獲取訪問令牌,但客戶端未創建身份驗證Cookie。每次嘗試訪問受保護的頁面時,都會使用訪問令牌獲取回調頁面。

我在這裏錯過了什麼?我目前的代碼如下。

有擔保控制器動作:

namespace MvcWebApp.Controllers 
{  
    public class SecuredController : Controller 
    { 
     // GET: Secured 
     [Authorize] 
     public ActionResult Index() 
     { 
      return View((User as ClaimsPrincipal).Claims); 
     } 
    } 
} 

啓動類:

public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     app.SetDefaultSignInAsAuthenticationType("ClientCookie"); 

     app.UseCookieAuthentication(new CookieAuthenticationOptions 
     { 
      AuthenticationMode = AuthenticationMode.Active, 
      AuthenticationType = "ClientCookie", 
      CookieName = CookieAuthenticationDefaults.CookiePrefix + "ClientCookie", 
      ExpireTimeSpan = TimeSpan.FromMinutes(5) 
     }); 

     // *************************************************************************** 
     // Approach 1 : ResponseType = "id_token token" 
     // *************************************************************************** 
     app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions 
     { 
      AuthenticationMode = AuthenticationMode.Active, 
      AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType, 
      SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(), 
      Authority = "https://thirdparty.com.au/oauth2", 
      ClientId = "_Th4GVMa0JSrJ8RKcZrzbcexk5ca", 
      ClientSecret = "a3GVJJbLHkrn9nJRj3IGNvk5eGQa", 
      RedirectUri = "http://mvcwebapp.local/", 
      ResponseType = "id_token token", 
      Scope = "openid", 

      Configuration = new OpenIdConnectConfiguration 
      { 
       AuthorizationEndpoint = "https://thirdparty.com.au/oauth2/authorize", 
       TokenEndpoint = "https://thirdparty.com.au/oauth2/token", 
       UserInfoEndpoint = "https://thirdparty.com.au/oauth2/userinfo", 
      }, 

      Notifications = new OpenIdConnectAuthenticationNotifications 
      { 
       SecurityTokenValidated = n => 
       { 
        var token = n.ProtocolMessage.AccessToken; 

        // persist access token in cookie 
        if (!string.IsNullOrEmpty(token)) 
        { 
         n.AuthenticationTicket.Identity.AddClaim(
          new Claim("access_token", token)); 
        } 

        return Task.FromResult(0); 
       }, 

       AuthenticationFailed = notification => 
       { 
        if (string.Equals(notification.ProtocolMessage.Error, "access_denied", StringComparison.Ordinal)) 
        { 
         notification.HandleResponse(); 

         notification.Response.Redirect("/"); 
        } 

        return Task.FromResult<object>(null); 
       } 
      } 
     }); 

     // *************************************************************************** 
     // Approach 2 : ResponseType = "code" 
     // *************************************************************************** 
     //app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions 
     //{ 
     // AuthenticationMode = AuthenticationMode.Active, 
     // AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType, 
     // SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(), 
     // Authority = "https://thirdparty.com.au/oauth2", 
     // ClientId = "_Th4GVMa0JSrJ8RKcZrzbcexk5ca", 
     // ClientSecret = "a3GVJJbLHkrn9nJRj3IGNvk5eGQa", 
     // RedirectUri = "http://mvcwebapp.local/", 
     // ResponseType = "code", 
     // Scope = "openid", 

     // Configuration = new OpenIdConnectConfiguration 
     // { 
     //  AuthorizationEndpoint = "https://thirdparty.com.au/oauth2/authorize", 
     //  TokenEndpoint = "https://thirdparty.com.au/oauth2/token", 
     //  UserInfoEndpoint = "https://thirdparty.com.au/oauth2/userinfo", 
     // }, 

     // Notifications = new OpenIdConnectAuthenticationNotifications 
     // { 
     //  AuthorizationCodeReceived = async (notification) => 
     //  { 
     //   using (var client = new HttpClient()) 
     //   { 
     //    var configuration = await notification.Options.ConfigurationManager.GetConfigurationAsync(notification.Request.CallCancelled);           
     //    var request = new HttpRequestMessage(HttpMethod.Get, configuration.TokenEndpoint); 
     //    request.Content = new FormUrlEncodedContent(new Dictionary<string, string> 
     //    { 
     //     {OpenIdConnectParameterNames.ClientId, notification.Options.ClientId}, 
     //     {OpenIdConnectParameterNames.ClientSecret, notification.Options.ClientSecret}, 
     //     {OpenIdConnectParameterNames.Code, notification.ProtocolMessage.Code}, 
     //     {OpenIdConnectParameterNames.GrantType, "authorization_code"}, 
     //     {OpenIdConnectParameterNames.ResponseType, "token"}, 
     //     {OpenIdConnectParameterNames.RedirectUri, notification.Options.RedirectUri} 
     //    }); 

     //    var response = await client.SendAsync(request, notification.Request.CallCancelled); 
     //    response.EnsureSuccessStatusCode(); 

     //    var payload = JObject.Parse(await response.Content.ReadAsStringAsync()); 

     //    // Add the access token to the returned ClaimsIdentity to make it easier to retrieve. 
     //    notification.AuthenticationTicket.Identity.AddClaim(new Claim(
     //     type: OpenIdConnectParameterNames.AccessToken, 
     //     value: payload.Value<string>(OpenIdConnectParameterNames.AccessToken))); 
     //   } 
     //  } 
     // } 

     //}); 

    } 
}    

回答

3

TL; DR:使用ResponseType = "id_token token"和它應該工作。在OpenID Connect中,response_type=token不被視爲合法值:http://openid.net/specs/openid-connect-core-1_0.html#Authentication

有時爲了向後兼容的原因實現,response_type=token不是由MSFT開發的中間件OIDC支持:當無id_token由ID連接提供者返回(這也排除了有效code流量)異常始終拋出。你可以找到更多關於這個其他SO post的信息。

(注:在SecurityTokenValidated,要替換使用n.AuthenticationTicket = new AuthenticationTicket(...)的OIDC中間件創建票證:它不是推薦的方法,將導致ClaimsIdentity缺少必要的索賠,您應該考慮刪除的分配和簡單地添加新的。 (access_token索賠)

+0

我試過response_type =「id_token令牌」,但它看起來像我使用的身份服務器(WSO2.0.0)確實支持它。我將不得不等待下一個版本發佈完整的openid連接功能。當我改變響應response_type =「code」時,它完成了認證過程的第一部分,並返回URL中的代碼,但下一個獲取訪問令牌的請求不會發生,也不會在OWIN管道中創建標識。 – TejSoft

+0

事實上,它似乎並不支持:http://stackoverflow.com/a/29140396/542757。不幸的是,你不能使用代碼流,因爲OIDC中間件不支持它(這是一種恥辱,我多次向ASP.NET團隊說過)。將遷移到ASP.NET 5是一個選項? – Pinpoint

+0

如果WSO2還沒有準備好,ASP.net 5會有幫助嗎? id服務器將支持多個站點,一些現有的和一些新的(正在構建)。新的可以使用ASP.net 5,但是舊的可以使用4.5。隨着WSO2即將發佈新版本,我可能會再等幾周。我用我提出的兩種方法更新了這個問題。 – TejSoft