摘要
我想要的是能够将自定义的AuthorizeAttribute添加到一个方法中,然后该方法被swagger识别,并显示可用的授权弹出。我遇到的问题是如何让IOperationFilter正确地使用IAuthorizationFilter。
代码
startup.cs
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
[Filters.Authorization2]
[HttpGet]
public ApiResult<List<Request>> GetRequest(int ID)Authorization2.cs
[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
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错误:
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.尝试1
我试着补充:
services.AddAuthentication(Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme);但我也犯了同样的错误。如果我试着:
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
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
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更新方法--对该方法的调用按预期工作,但现在每个方法都是锁,而不仅仅是具有属性的方法。
问题
如何修改我的代码,使其只具有带有属性的方法的锁,并正确地处理授权?
发布于 2021-02-04 16:36:07
以下是对另一个问题的答复:
https://stackoverflow.com/a/61365691/2885471
我设法让它开始工作了。本质上,我在SwaggerGen服务配置中创建了一个安全定义,将安全性需求放在IOperationFilter类中,然后将该类添加到OperationFilters中。
https://stackoverflow.com/questions/63292319
复制相似问题