2016-12-15 107 views
0

當我嘗試從受IdentityServer3保護的API訪問資源時,出現401錯誤。訪問由IdentityServer3保護的API時出現錯誤401

我可以登錄並從IdentityServer3的主機應用程序得到的access_token悄無聲息,但我不能使用的access_token消耗這些資源。

我配置我IdentityServer的主機在啓動類是這樣的:

public void Configuration(IAppBuilder app) 
{ 
    Log.Logger = new LoggerConfiguration() 
     .WriteTo.Trace() 
     .CreateLogger(); 

    AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject; 
    JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>(); 

    // Configure IdentityServer3 
    app.Map("/identity", configuration => 
    { 
     configuration.UseIdentityServer(new IdentityServerOptions 
     { 
      SiteName = "IdentityServer3 Sample", 
      SigningCertificate = LoadCertificate(), 
      Factory = ServiceFactory.Create(), 
      RequireSsl = true, 

      CspOptions = new CspOptions 
      { 
       Enabled = true, 
       FontSrc = "fonts.googleapis.com" 
      }, 

      AuthenticationOptions = new AuthenticationOptions 
      { 
       EnablePostSignOutAutoRedirect = true, 
      } 
     }); 
    }); 
} 

在我服務工廠類,我有:

public static IdentityServerServiceFactory Create() 
{ 
    var factory = new IdentityServerServiceFactory 
    { 
     ScopeStore = new Registration<IScopeStore>(
      new InMemoryScopeStore(Scopes.GetScopes())), 
     ClientStore = new Registration<IClientStore>(
      new InMemoryClientStore(Clients.GetClients())), 
     CorsPolicyService = new Registration<ICorsPolicyService>(
      new DefaultCorsPolicyService {AllowAll = true}) 
    }; 

    //factory.UseInMemoryUsers(Users.GetUsers()); 

    ConfigureServices(factory); 

    return factory; 
} 

private static void ConfigureServices(IdentityServerServiceFactory factory) 
{ 
    factory.UserService = new Registration<IUserService, UserService>(); 

    factory.Register(new Registration<BaseContext>(resolver => new BaseContext())); 

    factory.Register(new Registration<AppUserManager>(resolver => new AppUserManager(
     new UserStore<User>(resolver.Resolve<BaseContext>())))); 
} 

作用域

return new List<Scope> 
{ 
    StandardScopes.OpenId, 
    StandardScopes.Profile, 
    StandardScopes.OfflineAccess, 

    new Scope 
    { 
     Enabled = true, 
     Name = "roles", 
     Type = ScopeType.Identity, 
     IncludeAllClaimsForUser = true, 
     Claims = new List<ScopeClaim> 
     { 
      new ScopeClaim("role") 
     } 
    }, 

    new Scope 
    {      
     Enabled = true, 
     Name = "ro", 
     Type = ScopeType.Resource, 
     IncludeAllClaimsForUser = true, 
     Claims = new List<ScopeClaim> 
     { 
      new ScopeClaim("role") 
     } 
    } 
}; 

而且客戶

return new List<Client> 
{ 
    new Client 
    { 
     Enabled = true, 
     ClientName = "Hibrid Flow Client", 
     ClientId = AppIdentityConstants.ClientIdForHibridFlow, 
     Flow = Flows.Hybrid, 

     RequireConsent = false, 
     AccessTokenType = AccessTokenType.Reference, 
     UpdateAccessTokenClaimsOnRefresh = true, 

     ClientSecrets = new List<Secret> 
     { 
      new Secret(AppIdentityConstants.ClientSecret.Sha256()) 
     }, 
     AllowedScopes = new List<string> 
     { 
      Constants.StandardScopes.OpenId, 
      Constants.StandardScopes.Profile, 
      Constants.StandardScopes.Email, 
      Constants.StandardScopes.Roles, 
      Constants.StandardScopes.OfflineAccess, 
     }, 
     RedirectUris = new List<string> 
     { 
      AppIdentityConstants.IdentityAddress, 
      AppIdentityConstants.CRMAddress 
     }, 
     PostLogoutRedirectUris = new List<string> 
     { 
      AppIdentityConstants.IdentityAddress, 
      AppIdentityConstants.CRMAddress 
     }, 
     LogoutSessionRequired = true 
    }, 

    new Client 
    { 
     Enabled = true, 
     ClientName = "Resource Owner Client", 
     ClientId = AppIdentityConstants.ClientIdForResourceOwnerFlow, 
     Flow = Flows.ResourceOwner, 

     RequireConsent = false, 
     AccessTokenType = AccessTokenType.Jwt, 
     UpdateAccessTokenClaimsOnRefresh = true, 
     AccessTokenLifetime = 3600, 

     ClientSecrets = new List<Secret> 
     { 
      new Secret(AppIdentityConstants.ClientSecret.Sha256()) 
     }, 
     AllowedScopes = new List<string> 
     { 
      Constants.StandardScopes.OpenId, 
      Constants.StandardScopes.Profile, 
      Constants.StandardScopes.Email, 
      Constants.StandardScopes.Roles, 
      Constants.StandardScopes.OfflineAccess, 
      "ro" 
     }, 
     AllowAccessTokensViaBrowser = true, 
     AbsoluteRefreshTokenLifetime = 86400, 
     SlidingRefreshTokenLifetime = 43200, 
     RefreshTokenUsage = TokenUsage.OneTimeOnly, 
     RefreshTokenExpiration = TokenExpiration.Sliding 
    }, 
}; 

這是IdentityServer3的主機應用程序的源代碼。

現在我會告訴你我是如何設置API的。 這是我啓動類:

public void Configuration(IAppBuilder app) 
{ 
    JwtSecurityTokenHandler.InboundClaimTypeMap.Clear(); 

    app.UseIdentityServerBearerTokenAuthentication(
     new IdentityServerBearerTokenAuthenticationOptions 
    { 
     Authority = AppIdentityConstants.IdentityBaseAddress, 
     RequiredScopes = new[] { "ro", "offline_access" }, 
     ClientId = AppIdentityConstants.ClientIdForResourceOwnerFlow, 
     ClientSecret = AppIdentityConstants.ClientSecret, 
    }); 
} 

AppIdentityConstants.IdentityBaseAddresshttps://localhost:44342/identity

而且,在Global.asax.cs中我把這些配置:

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     // Web API configuration and services 
     config.Formatters.Remove(config.Formatters.XmlFormatter); 

     var formatters = GlobalConfiguration.Configuration.Formatters; 
     var jsonFormatter = formatters.JsonFormatter; 
     var settings = jsonFormatter.SerializerSettings; 

     #if DEBUG 
     settings.Formatting = Formatting.Indented; 
     #endif 

     settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

     // Web API routes 
     config.MapHttpAttributeRoutes(); 

     config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 

     config.Routes.MapHttpRoute(
      name: "DefaultApi", 
      routeTemplate: "api/{controller}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 
    } 
} 

而且AuthorizeAttribute過濾器:

public class FilterConfig 
{ 
    public static void RegisterGlobalFilters(HttpConfiguration configuration) 
    { 
     configuration.Filters.Add(new AuthorizeAttribute()); 
    } 
} 

爲了測試我做了以下內容:

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8" /> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
</head> 
<body> 
    <script src="bower_components/jquery/dist/jquery.min.js"></script> 
    <script> 
     function done(response) { console.log(response); } 
     function always(response) { console.log("always"); } 
     function fail(response) { console.log("fail"); } 
     var custom = { 
      client_id: "ro", 
      client_secret: "client_secret", 
      scope: "ro offline_access", 
     }; 

     $(function() { 
      var settings = { 
       "async": true, 
       "crossDomain": true, 
       "url": "https://localhost:44342/identity/connect/token", 
       "method": "POST", 
       "headers": { 
        "content-type": "application/x-www-form-urlencoded", 
        "cache-control": "no-cache" 
       }, 
       "data": { 
        "client_id": custom.client_id, 
        "client_secret": custom.client_secret, 
        "scope": custom.scope, 
        "username": "[email protected]", 
        "password": "123456", 
        "grant_type": "password" 
       } 
      } 
      $.ajax(settings).done(function (response){ 
       done(response); 
       checkStatus(response.access_token); 
      }).always(always).fail(fail); 

      function checkStatus(access_token) { 
       var settings2 = { 
        "async": true, 
        "crossDomain": true, 
        "url": "https://localhost:44352/api/importer/status", 
        "method": "GET", 
        xhrFields: { 
         withCredentials: true 
        }, 
        "headers": { 
         "Authorization": "Bearer " + access_token, 
         "cache-control": "no-cache" 
        } 
       } 
       $.ajax(settings2).done(done).always(always).fail(fail); 
      } 
     }); 
    </script> 
</body> 
</html> 

第一個獲取訪問數據的請求,包括acess_token,已成功完成。

但是,對API做出的第二個請求返回401錯誤。
而且正如我前面所示,API受AuthorizeAttribute保護。

出了什麼問題?

回答

3

如果您調試了checkStatus函數,那麼acessData參數是否具有access_token屬性?

如果是這樣,那麼您是否在您的Web API項目中安裝了Microsoft.Owin.Host.SystemWeb NuGet包?可能發生的情況是,您的OWIN管道未執行,因爲您錯過了該軟件包。因此,訪問令牌不會轉換爲身份,請求保持未經身份驗證,這可以解釋HTTP 401響應。

+0

「Microsoft.Owin.Host.SystemWeb」的安裝工作。但是我得到了一個WWW-Authenticate→承載錯誤=「insufficient_scope」錯誤。你知道會發生什麼嗎?你可以幫我嗎? – JamesTK

+0

簡單來說,IdentityServerBearerTokenAuthenticationOptions的'RequiredScopes'屬性是一個數組,我通知單個在線範圍。解決了! – JamesTK

相關問題