当我尝试从受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.IdentityBaseAddress
是https://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保护。
出了什么问题?
“Microsoft.Owin.Host.SystemWeb”的安装工作。但是我得到了一个WWW-Authenticate→承载错误=“insufficient_scope”错误。你知道会发生什么吗?你可以帮我吗? – JamesTK
简单来说,IdentityServerBearerTokenAuthenticationOptions的'RequiredScopes'属性是一个数组,我通知单个在线范围。解决了! – JamesTK