使用 .net 4.5 通过 identityserver3 验证 swagger
Authenticating swagger with identityserver3 using .net 4.5
我在大摇大摆地使用 oauth2 时遇到了一些问题。
我在我的数据库中创建了一个这样的客户端:
private static void CreateSwaggerClient(DatabaseContext context)
{
var client = new Client
{
ClientId = "swaggerui",
ClientName = "Swagger UI client",
Flow = Flows.Implicit,
Enabled = true,
EnableLocalLogin = true,
AccessTokenType = AccessTokenType.Reference,
AllowAccessTokensViaBrowser = true,
IdentityTokenLifetime = 300,
AccessTokenLifetime = 3600,
AuthorizationCodeLifetime = 300,
AbsoluteRefreshTokenLifetime = 2592000,
SlidingRefreshTokenLifetime = 1296000,
RedirectUris = new List<ClientRedirectUri>
{
new ClientRedirectUri { Uri = "http://localhost:62668/swagger" }
},
AllowedScopes = new List<ClientScope>()
{
new ClientScope
{
Scope = "api"
}
},
ClientSecrets = new List<ClientSecret>()
{
new ClientSecret
{
Value = "secret".Sha256(),
Type = "SharedSecret"
}
}
};
context.Clients.Add(client);
context.SaveChanges();
}
可以访问我的 api 范围:
private static void CreateScope(DatabaseContext context)
{
var scope = new Scope
{
Enabled = true,
Name = "api",
DisplayName = "Cormar API",
Description = "Should only be used for trusted internal service side applications",
Required = true,
Emphasize = true,
Type = (int)ScopeType.Resource,
IncludeAllClaimsForUser = false,
ShowInDiscoveryDocument = true,
AllowUnrestrictedIntrospection = true,
ScopeClaims = new List<ScopeClaim>()
{
new ScopeClaim
{
Name = "role",
Description = "Role claim types",
AlwaysIncludeInIdToken = true
},
new ScopeClaim
{
Name = "name",
Description = "The name of the user",
AlwaysIncludeInIdToken = true
},
new ScopeClaim
{
Name ="password",
Description = "Contains the encrypted password for a user",
AlwaysIncludeInIdToken = true
}
},
ScopeSecrets = new List<ScopeSecret>()
{
new ScopeSecret
{
Value = "anothersecret".Sha256(),
Type = "SharedSecret"
}
}
};
context.Scopes.Add(scope);
context.SaveChanges();
}
如果我打开浏览器并导航到授权 url,如下所示:https://localhost:44313/identity/connect/authorize?client_id=swaggerui&redirect_uri=http://localhost:62668/swagger&response_type=token&scope=api&state=moo 它会将我带到登录页面,当我输入用户名和密码时,我会进入 swagger 页面access_token 附加到 URL,如下所示:
#access_token=b49fe5641519c325c17d248d2372d69f&token_type=Bearer&expires_in=3600&scope=api&state=moo
但这里的问题是,如果我单击任何内容,访问令牌将从 url 中删除,如果我尝试我的任何端点,它们都会因访问被拒绝而失败。
我已经像这样设置了我的 swagger 配置:
private static void ConfigureSwagger(HttpConfiguration config)
{
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "test API");
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".XML";
var commentsFile = Path.Combine(baseDirectory, "bin", commentsFileName);
c.IncludeXmlComments(commentsFile);
c.OAuth2("oauth2")
.Description("OAuth2 Implicit Grant")
.Flow("implicit")
.AuthorizationUrl("http://localhost:62668/identity/connect/authorize")
.TokenUrl("http://localhost:62668/identity/connect/token")
.Scopes(scopes =>
{
scopes.Add("api", "api access");
});
c.OperationFilter<AssignOAuth2SecurityRequirements>();
}).EnableSwaggerUi(c =>
{
c.EnableOAuth2Support("swaggerui", "secret", "local", "test");
});
}
谁能告诉我我错过了什么?
我设法让它工作了。
首先,我的 AssignOAuth2SecurityRequirements
设置不正确。我实际上在这里找到了正确的代码:http://knowyourtoolset.com/2015/08/secure-web-apis-with-swagger-swashbuckle-and-oauth2-part-2/
public class AssignOAuth2SecurityRequirements: IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var actFilters = apiDescription.ActionDescriptor.GetFilterPipeline();
var allowsAnonymous = actFilters.Select(f => f.Instance).OfType<OverrideAuthorizationAttribute>().Any();
if (allowsAnonymous)
return; // must be an anonymous method
//var scopes = apiDescription.ActionDescriptor.GetFilterPipeline()
// .Select(filterInfo => filterInfo.Instance)
// .OfType<AllowAnonymousAttribute>()
// .SelectMany(attr => attr.Roles.Split(','))
// .Distinct();
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{"oauth2", new List<string> {"api"}}
};
operation.security.Add(oAuthRequirements);
}
}
接下来,我客户的 redirect_uris 不正确。它们都必须是 https 并且它们需要完整的重定向 uri。我的变成了这个:
new ClientRedirectUri { Uri = "https://localhost:44313/swagger/ui/o2c-html" },
一旦这些都设置好了,一切就开始了。
我在大摇大摆地使用 oauth2 时遇到了一些问题。 我在我的数据库中创建了一个这样的客户端:
private static void CreateSwaggerClient(DatabaseContext context)
{
var client = new Client
{
ClientId = "swaggerui",
ClientName = "Swagger UI client",
Flow = Flows.Implicit,
Enabled = true,
EnableLocalLogin = true,
AccessTokenType = AccessTokenType.Reference,
AllowAccessTokensViaBrowser = true,
IdentityTokenLifetime = 300,
AccessTokenLifetime = 3600,
AuthorizationCodeLifetime = 300,
AbsoluteRefreshTokenLifetime = 2592000,
SlidingRefreshTokenLifetime = 1296000,
RedirectUris = new List<ClientRedirectUri>
{
new ClientRedirectUri { Uri = "http://localhost:62668/swagger" }
},
AllowedScopes = new List<ClientScope>()
{
new ClientScope
{
Scope = "api"
}
},
ClientSecrets = new List<ClientSecret>()
{
new ClientSecret
{
Value = "secret".Sha256(),
Type = "SharedSecret"
}
}
};
context.Clients.Add(client);
context.SaveChanges();
}
可以访问我的 api 范围:
private static void CreateScope(DatabaseContext context)
{
var scope = new Scope
{
Enabled = true,
Name = "api",
DisplayName = "Cormar API",
Description = "Should only be used for trusted internal service side applications",
Required = true,
Emphasize = true,
Type = (int)ScopeType.Resource,
IncludeAllClaimsForUser = false,
ShowInDiscoveryDocument = true,
AllowUnrestrictedIntrospection = true,
ScopeClaims = new List<ScopeClaim>()
{
new ScopeClaim
{
Name = "role",
Description = "Role claim types",
AlwaysIncludeInIdToken = true
},
new ScopeClaim
{
Name = "name",
Description = "The name of the user",
AlwaysIncludeInIdToken = true
},
new ScopeClaim
{
Name ="password",
Description = "Contains the encrypted password for a user",
AlwaysIncludeInIdToken = true
}
},
ScopeSecrets = new List<ScopeSecret>()
{
new ScopeSecret
{
Value = "anothersecret".Sha256(),
Type = "SharedSecret"
}
}
};
context.Scopes.Add(scope);
context.SaveChanges();
}
如果我打开浏览器并导航到授权 url,如下所示:https://localhost:44313/identity/connect/authorize?client_id=swaggerui&redirect_uri=http://localhost:62668/swagger&response_type=token&scope=api&state=moo 它会将我带到登录页面,当我输入用户名和密码时,我会进入 swagger 页面access_token 附加到 URL,如下所示:
#access_token=b49fe5641519c325c17d248d2372d69f&token_type=Bearer&expires_in=3600&scope=api&state=moo
但这里的问题是,如果我单击任何内容,访问令牌将从 url 中删除,如果我尝试我的任何端点,它们都会因访问被拒绝而失败。 我已经像这样设置了我的 swagger 配置:
private static void ConfigureSwagger(HttpConfiguration config)
{
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "test API");
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".XML";
var commentsFile = Path.Combine(baseDirectory, "bin", commentsFileName);
c.IncludeXmlComments(commentsFile);
c.OAuth2("oauth2")
.Description("OAuth2 Implicit Grant")
.Flow("implicit")
.AuthorizationUrl("http://localhost:62668/identity/connect/authorize")
.TokenUrl("http://localhost:62668/identity/connect/token")
.Scopes(scopes =>
{
scopes.Add("api", "api access");
});
c.OperationFilter<AssignOAuth2SecurityRequirements>();
}).EnableSwaggerUi(c =>
{
c.EnableOAuth2Support("swaggerui", "secret", "local", "test");
});
}
谁能告诉我我错过了什么?
我设法让它工作了。
首先,我的 AssignOAuth2SecurityRequirements
设置不正确。我实际上在这里找到了正确的代码:http://knowyourtoolset.com/2015/08/secure-web-apis-with-swagger-swashbuckle-and-oauth2-part-2/
public class AssignOAuth2SecurityRequirements: IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var actFilters = apiDescription.ActionDescriptor.GetFilterPipeline();
var allowsAnonymous = actFilters.Select(f => f.Instance).OfType<OverrideAuthorizationAttribute>().Any();
if (allowsAnonymous)
return; // must be an anonymous method
//var scopes = apiDescription.ActionDescriptor.GetFilterPipeline()
// .Select(filterInfo => filterInfo.Instance)
// .OfType<AllowAnonymousAttribute>()
// .SelectMany(attr => attr.Roles.Split(','))
// .Distinct();
if (operation.security == null)
operation.security = new List<IDictionary<string, IEnumerable<string>>>();
var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
{
{"oauth2", new List<string> {"api"}}
};
operation.security.Add(oAuthRequirements);
}
}
接下来,我客户的 redirect_uris 不正确。它们都必须是 https 并且它们需要完整的重定向 uri。我的变成了这个:
new ClientRedirectUri { Uri = "https://localhost:44313/swagger/ui/o2c-html" },
一旦这些都设置好了,一切就开始了。