2016-12-15 106 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

相关问题