首页 文章

我'm not getting a scope checkbox when the Authorize tag doesn' t包含角色,Ajax授权请求也没有发送范围

提问于
浏览
2

UPDATE 2: 如果我从此更改我的控制器授权标签

[Authorize]

对此

[Authorize(Roles = "Read")]

然后我得到范围选择的复选框,ajax令牌请求包含正确的范围并成功完成 . 然而,我仍然以红色感叹号结束 . It looks like Swagger or Swashbuckle is requiring that the roles match the scope definitions? Is it possible to use the application flow with no Roles defined when using Swashbuckle? And if so how do you get that to work? 我是否必须在操作过滤器类中手动设置范围?如果在Authorize标记中没有列出Roles就无法使用Swashbuckle,那么我需要知道如何在IdentityServer3中分配客户端角色 .

UPDATE 3 如果我将操作过滤器更改为类似的范围,则会显示范围,但在选择范围并单击“授权”后,页面才会重新加载 . 首先成功发送了ajax授权 . This is closer, but the authorization still doesn't stick (not sure what term to use here, but stick seems to sum it up.) How do I get the authorization to stick?

public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{

    var scopes = new List<string>() { "Read" };

    if (scopes.Any())
    {
        if (operation.security == null)
            operation.security = new List<IDictionary<string, IEnumerable<string>>>();

        var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
        {
            { "oauth2", scopes }
        };

        operation.security.Add(oAuthRequirements);
    }
}

Original Post 我正在尝试配置Swashbuckle以允许客户端测试受OAuth2客户端凭据流保护的REST服务 . The toggle never appears on the page, should it? ,但我确实得到一个带有感叹号的红色圆圈,告诉我资源没有受到保护 . 我正在使用nuget包Swashbuckle.Core版本5.4.0 . 答案在这里Enable Oauth2 client credentials flow in Swashbuckle似乎遵循我注入任何javascript而不是希望意味着我没有找到缺失的链接 . 由于此Flow是"application"并且我只有一个作用域,我想确保它看起来配置正确并且clientSecret加载到正确的位置 .

UPDATE 1 I've been able to debug the AJAX call and can see that the scope is not set and therefor not sent in the request. Why is the scope not being set? Why don't I have a checkbox to select the scope?

这是我的SwaggerConfig.cs

public class SwaggerConfig
{
    public static void Register()
    {
        var thisAssembly = typeof(SwaggerConfig).Assembly;

        GlobalConfiguration.Configuration
            .EnableSwagger(c =>
            {
                c.SingleApiVersion("v1", "waRougeOneApp");
                c.OAuth2("oauth2")
                    .Description("OAuth2 Client Credentials Grant Flow")
                    .Flow("application")
                    .TokenUrl("https://securitydev.rougeone.com/core/connect/token")
                    .Scopes(scopes =>
                    {
                        scopes.Add("Read", "Read access to protected resources");
                    });
                c.IncludeXmlComments(GetXmlCommentsPath());
                c.UseFullTypeNameInSchemaIds();
                c.DescribeAllEnumsAsStrings();
                c.OperationFilter<AssignOAuth2SecurityRequirements>();
            })
            .EnableSwaggerUi(c =>
            {
                c.EnableOAuth2Support(
                    clientId: "client_id",
                    clientSecret: "client_secret",
                    realm: "swagger-realm",
                    appName: "Swagger UI"
                );
            });
    }

    protected static string GetXmlCommentsPath()
    {
        return System.String.Format(@"{0}bin\\waRougeOne.xml", System.AppDomain.CurrentDomain.BaseDirectory);
    }
}

AssignOAuth2SecurityRequirements类是

public class AssignOAuth2SecurityRequirements : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
        var authorized = apiDescription.ActionDescriptor.GetCustomAttributes<AuthorizeAttribute>();
        if (!authorized.Any()) return;

        if (operation.security == null)
            operation.security = new List<IDictionary<string, IEnumerable<string>>>();

        var oAuthRequirements = new Dictionary<string, IEnumerable<string>>
  {
      {"oauth2", Enumerable.Empty<string>()}
  };

        operation.security.Add(oAuthRequirements);
    }
}

我一直试图找到一个客户端凭据流程的工作示例,但没有成功,所以我不能100%确定当一切正常时我会看到一个切换按钮 . 在隐藏流程的示例中,如果将鼠标悬停在红色感叹圈上,则会看到列出的授权类型,单击红色感叹号圆圈会显示列出的范围选项,您可以在其中选择一个,然后单击授权,然后返回蓝色感叹号 .

对我来说,我从来没有选中一个范围的复选框,但我只定义了一个范围 . 我究竟做错了什么?我在调试swagger ui JavaScript时发现了这个,它似乎指向它需要的所有数据?

authorizations
:
null
auths
:
Array[1]
0
:
Object
name
:
"oauth2"
type
:
"oauth2"
value
:
Object
description
:
"OAuth2 Client Credentials Grant Flow"
flow
:
"application"
scopes
:
Object
Read
:
"Read access to protected resources"
__proto__
:
Object
tokenUrl
:
"https://security.starrwarrs.com/core/connect/token"
type
:
"oauth2"
__proto__
:
Object
__proto__
:
Object
length
:
1
__proto__
:
Array[0]

2 回答

  • 1

    这些是我们已经完成和工作的步骤:

    • 在SwaggerConfig文件中,添加以下设置:

    c.OAuth2(“oauth2”)
    .Description(“OAuth2隐式授权”)
    流式细胞(“隐式”)
    .AuthorizationUrl(swaggerConfigurations [ “IssuerUri”] . 的ToString())
    .Scopes(范围=>
    {
    scopes.Add(“user_impersonation”,“Access REST API”);
    });

    属性是:

    • 授权方案的名称(上例中的oauth2)

    • 授权方案说明

    • Flow - 要使用的授权类型

    • 授权网址 - 应该是STS网址(例如:https://auth2.test.com/oauth2/authorize

    • 范围 - 范围名称

    II . 在SwaggerConfig文件中,在swagger ui配置部分下也添加以下设置:

    c.EnableOAuth2Support(swaggerConfigurations["ClientId"].ToString(), string.Empty, swaggerConfigurations["RedirectUri"].ToString(), "Swagger", " ", new Dictionary<string, string> { { "resource", WebApi.Utility.GetAudiences().First() } });
    

    该方法接受以下参数:

    • clientId - 这应该是安全令牌服务中配置的swagger的客户端ID

    • clientSecret - 这应该是客户端密钥 . 仅在代码授予类型的情况下才需要这样做

    • 领域 - 这应该是重定向网址(这应该是[基地址] swagger / ui / o2c-html)

    • appName - 这应该是昂首阔步

    • scopeSeperator - 如果只有作用域,则不需要传递

    • additionalQueryStringParams - 这应该包含有效受众列表,这对应于为其颁发令牌的资源 .

    III . 在web api项目中创建一个新的Operation Filter,如下所示:

    public class AssignOperationFilters : IOperationFilter
        {              
            public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
            {     
                string clientId = "clientID";
                if (apiDescription != null)
                {
                    var actFilters = apiDescription.ActionDescriptor.GetFilterPipeline();
    
                    var allowsAnonymous = actFilters.Select(f => f.Instance).OfType<OverrideAuthorizationAttribute>().Any();
                    if (allowsAnonymous)
                    {
                        return; // must be an anonymous method
                    }
                }
    
                if (operation != null)
                {
                    if (operation.security == null)
                    {
                        operation.security = new List<IDictionary<string, IEnumerable<string>>>();
                    }
    
                    var authRequirements = new Dictionary<string, IEnumerable<string>>
                    {
                        { "oauth2", new List<string> { clientId } }
                    };
    
                    operation.security.Add(authRequirements);
                }
            }
        }
    

    此类将用于将OAuth范围绑定到各个操作

    IV . 在swagger配置文件中添加上面的过滤器(参见下面的代码)

    c.OperationFilter<AssignOperationFilters>();
    

    V.在安全令牌服务中配置客户端ID,密钥,重定向URL和资源

    VI . 在Web API项目中,如果有一个index.html用于注入特定于API的UI字段/样式,那么请确保所有的javascript代码都保留在原始版本的index.html文件的Swashbuckle中(如位置 - https://github.com/domaindrivendev/Swashbuckle/blob/master/Swashbuckle.Core/SwaggerUi/CustomAssets/index.html

  • 1

    Solution!! 最后一部分是最难以弄清楚的,我最终在Chrome开发者工具的帮助下做了这一点,在网络标签上显示了一点红色X,显示以下错误消息:

    XMLHttpRequest cannot load http://security.RogueOne.com/core/connect/token. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:62561' is therefore not allowed access.
    

    错误消息最终连接点在此之前,将调用on OAuthComplete完整的JavaScript函数,但没有令牌 . 网络选项卡显示“此请求没有可用的响应数据”,但我会在响应标头中看到内容类型为Json的Content-Length . Fiddler还展示了看起来像(并且是)格式良好的JSON的响应 .

    我在这里描述了这个错误Swagger UI not parsing reponse,这是由于IdentityServer3正确没有添加“Access-Control-Allow-Origin:http://localhost:62561”的响应头,您可以强制IdentityServer3通过将客户端创建更新为以下内容来发送该头:

    new Client
    {
        ClientName = "SwaggerUI",
        Enabled = true,
        ClientId = "swaggerUI",
        ClientSecrets = new List<Secret>
        {
            new Secret("PasswordGoesHere".Sha256())
        },
        Flow = Flows.ClientCredentials,
        AllowClientCredentialsOnly = true,
        AllowedScopes = new List<string>
        {
            "Read"
        },
    
        Claims = new List<Claim>
        {
            new Claim("client_type", "headless"),
            new Claim("client_owner", "Portal"),
            new Claim("app_detail", "allow")
        },
        PrefixClientClaims = false
        // Add the AllowedCorOrigins to get the Access-Control-Allow-Origin header to be inserted for the following domains
        ,AllowedCorsOrigins = new List<string>
        {
            "http://localhost:62561/"
            ,"http://portaldev.RogueOne.com"
            ,"https://portaldev.RogueOne.com"
        }
    }
    

    AllowedCorsOrigins是我拼图的最后一块 . 希望这可以帮助面临同样问题的其他人

相关问题