首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IAuthorizationFilter和IOperationFilter的装腔作势

IAuthorizationFilter和IOperationFilter的装腔作势
EN

Stack Overflow用户
提问于 2020-08-06 21:57:12
回答 1查看 4.4K关注 0票数 0

摘要

我想要的是能够将自定义的AuthorizeAttribute添加到一个方法中,然后该方法被swagger识别,并显示可用的授权弹出。我遇到的问题是如何让IOperationFilter正确地使用IAuthorizationFilter。

代码

startup.cs

代码语言:javascript
复制
        services.AddSwaggerGen(c =>
       {
           c.SwaggerDoc("v2", new OpenApiInfo { Title = "API", Version = "v2" });
           // Adds "(Auth)" to the summary so that you can see which endpoints have Authorization
           c.OperationFilter<AppendAuthorizeToSummaryOperationFilter<Filters.Authorization2>>();

           c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
           {
               Name = "Bearer",
               Description = "Standard Authorization header using the SessionKey scheme. Example: \"{token}\"",
               In = ParameterLocation.Header,
               Type = SecuritySchemeType.ApiKey
           });

           c.OperationFilter<Filters.AuthorizeCheckOperationFilter>();
       });

controller.cs

代码语言:javascript
复制
    [Filters.Authorization2]
    [HttpGet]
    public ApiResult<List<Request>> GetRequest(int ID)

Authorization2.cs

代码语言:javascript
复制
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class Authorization2 : AuthorizeAttribute, IAuthorizationFilter
{
    public Authorization2()
    {

    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        //Get the session from the cache
        Session sess = GetSession(context.HttpContext);
        if (sess.IsValid)
        {
            //set sess
        }
        else
        {
            //If it's not there then return with bad news
            context.Result = Unauthorized();
            context.HttpContext.Response.StatusCode = 401;
        }
    }
}

AuthorizeCheckOperationFilter.cs

代码语言:javascript
复制
internal class AuthorizeCheckOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        context.ApiDescription.TryGetMethodInfo(out var methodInfo);

        if (methodInfo == null)
            return;

        var hasAuthorizeAttribute = false;

        if (methodInfo.MemberType == MemberTypes.Method)
        {
            // NOTE: Check the controller itself has Authorize attribute
            hasAuthorizeAttribute = methodInfo.DeclaringType.GetCustomAttributes(true).OfType<Authorization2>().Any();

            // NOTE: Controller has Authorize attribute, so check the endpoint itself.
            //       Take into account the allow anonymous attribute
            if (hasAuthorizeAttribute)
                hasAuthorizeAttribute = !methodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any();
            else
                hasAuthorizeAttribute = methodInfo.GetCustomAttributes(true).OfType<Authorization2>().Any();
        }

        if (!hasAuthorizeAttribute)
            return;

        if (!operation.Responses.Any(r => r.Key == StatusCodes.Status401Unauthorized.ToString()))
            operation.Responses.Add(StatusCodes.Status401Unauthorized.ToString(), new OpenApiResponse { Description = "Unauthorized" });
        if (!operation.Responses.Any(r => r.Key == StatusCodes.Status403Forbidden.ToString()))
            operation.Responses.Add(StatusCodes.Status403Forbidden.ToString(), new OpenApiResponse { Description = "Forbidden" });

        // NOTE: This adds the "Padlock" icon to the endpoint in swagger, 
        //       we can also pass through the names of the policies in the string[]
        //       which will indicate which permission you require.
        operation.Security = new List<OpenApiSecurityRequirement>
    {
        new OpenApiSecurityRequirement
        {
            {
                new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                    },
                    Scheme = "oauth2",
                    Name = "Bearer",
                    In = ParameterLocation.Header
                },
                new List<string>()
            }
        }
    };
    }
}

对于代码本身,将显示端点上的挂锁并设置标头,但该方法抛出一个500错误:

代码语言:javascript
复制
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.

尝试1

我试着补充:

代码语言:javascript
复制
services.AddAuthentication(Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme);

但我也犯了同样的错误。如果我试着:

代码语言:javascript
复制
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
                    options =>
                    {
                        options.LoginPath = new PathString("/auth/login");
                        options.AccessDeniedPath = new PathString("/auth/denied");
                    });

我的请求重定向到loginPath,这会导致404。

企图2

如果尝试使用不同的处理方法,并按如下方式使用TypeFilterAttribute:

修改startup.cs

代码语言:javascript
复制
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            },
                            Scheme = "oauth2",
                            Name = "Bearer",
                            In = ParameterLocation.Header,

                        },
                        new List<string>()
                    }
                });
//c.OperationFilter<Filters.AuthorizeCheckOperationFilter>();

Authorization.cs

代码语言:javascript
复制
public class AuthorizationHandler : IAuthorizationFilter
{
    public AuthorizationHandler()
    {

    }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        //Get the session from the cache
        Session sess = GetSession(context.HttpContext);
        if (sess.IsValid)
        {
            //set sess
        }
        else
        {
            //If it's not there then return with bad news
            context.Result = Unauthorized();
            context.HttpContext.Response.StatusCode = 401;
        }
    }
}

public class AuthorizeAttribute : TypeFilterAttribute 
{
    public AuthorizeAttribute() : base(typeof(AuthorizationHandler))
    {

    }
}

使用Filters.Authorize更新方法--对该方法的调用按预期工作,但现在每个方法都是锁,而不仅仅是具有属性的方法。

问题

如何修改我的代码,使其只具有带有属性的方法的锁,并正确地处理授权?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-04 16:36:07

以下是对另一个问题的答复:

https://stackoverflow.com/a/61365691/2885471

我设法让它开始工作了。本质上,我在SwaggerGen服务配置中创建了一个安全定义,将安全性需求放在IOperationFilter类中,然后将该类添加到OperationFilters中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63292319

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档