首页 文章

在Swashbuckle中启用Oauth2客户端凭据流

提问于
浏览
11

我使用IdentityServer3来保护具有客户端凭据授权的Web API . 对于文档我使用Swashbuckle但无法弄清楚如何在SwaggerConfig中为客户端凭据(应用程序)流启用Oauth2 . 任何帮助,将不胜感激!

2 回答

  • 4

    我在使这一切工作时遇到了一些麻烦,但经过大量的坚持后,我找到了一个无需将任何JavaScript注入SwaggerUI的解决方案 . 注意:我的部分困难可能是由于使用IdentityServer3,这是一个很棒的产品,只是不知道配置问题 .

    我的大多数更改都类似于上面的账单回答,但我的操作过滤器是不同的 . 在我的控制器中,所有方法都有一个没有角色的Authorize标签,如下所示:

    [Authorize]
    // Not this
    [Authorize(Roles = "Read")] // This doesn't work for me.
    

    如果Authorize标记上没有定义Roles,则OperationFilter如下所示:

    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            // Correspond each "Authorize" role to an oauth2 scope, since I don't have any "Roles" defined, this didn't work
            // and is in most of the Apply methods I found online.  If you are like me and your [Authorize] tag doesn't contain
            // any roles this will not work.
            //var scopes = apiDescription.ActionDescriptor.GetFilterPipeline()
            //    .Select(filterInfo => filterInfo.Instance)
            //    .OfType<AuthorizeAttribute>()
            //    .SelectMany(attr => attr.Roles.Split(','))
            //    .Distinct();
    
            var scopes = new List<string>() { "Read" }; // For me I just had one scope that is added to all all my methods, you might have to be more selective on how scopes are added.
    
            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);
            }
        }
    

    SwaggerConfig看起来像这样:

    public static void Register()
    {
        var thisAssembly = typeof(SwaggerConfig).Assembly;
        GlobalConfiguration.Configuration
            .EnableSwagger(c =>
            {
               c.SingleApiVersion("v1", "waPortal");
               c.OAuth2("oauth2")
                    .Description("OAuth2 Client Credentials Grant Flow")
                    .Flow("application")
                    .TokenUrl("http://security.RogueOne.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: "swaggerUI",
                    clientSecret: "BigSecretWooH00",
                    realm: "swagger-realm",
                    appName: "Swagger UI"
                );
            });
    }
    

    最后一部分是最难以弄清楚的,我最终在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.
    

    我在这里描述了这个错误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是我拼图的最后一块 . 希望这可以帮助面临同样问题的其他人

  • 9

    我能够让这个工作 . 大部分答案都可以找到here .

    我必须更改一些部分才能使client_credential授权生效 . 第一部分是在EnableSwagger和EnableSwaggerUi调用中:

    config.EnableSwagger(c => 
      {
        c.SingleApiVersion("v1", "sample api");
        c.OAuth2("oauth2")
         .Description("client credentials grant flow")
         .Flow("application")
         .Scopes(scopes => scopes.Add("sampleapi", "try out the sample api"))
         .TokenUrl("http://authuri/token");
        c.OperationFilter<AssignOAuth2SecurityRequirements>();
      }).EnableSwaggerUi(c =>
      {
        c.EnableOAuth2Support("sampleapi", "samplerealm", "Swagger UI");
      });
    

    这里重要的变化是 .Flow("application") 我也使用了 .TokenUrl 调用而不是 .AuthorizationUrl 这只是依赖于您设置的特定授权方案 .

    我也使用了稍微不同的 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);
        }
    }
    

    这应足以让身份验证开关显示 . 另一个问题是我设置了默认的身份验证对话框,因此用户只需选择一个范围,然后单击“授权” . 在我的情况下,由于我设置了身份验证的方式,这不起作用 . 我不得不在swagger-oauth.js脚本中重新编写对话框并将其注入SwaggerUI .

相关问题