• AuthorizeCheckOperationFilter


    Asp.Net Core: Swagger 与 Identity Server 4

     

    Swagger不用多说,可以自动生成Web Api的接口文档和客户端调用代码,方便开发人员进行测试。通常我们只需要几行代码就可以实现这个功能:

    ...
    builder.Services.AddSwaggerGen();
    ...
    app.UseSwagger();
    app.UseSwaggerUI();
    ...
    

    可如果使用Identity Server 4等认证服务对Web Api进行保护后,使用上面代码生成的Web Api文档就无法工作了,在进行测试时会提示401错误。

    本文介绍如何使Swagger在Identity Server 4认证服务保护下工作。

    配置Identity Server 4

    首先,使用开源的Identity Server 4 Admin搭建认证服务,这部分工作在系列文章《Identity Server 4 从入门到落地》中有详细的介绍,这里不再重复。

    准备测试用Web Api

    接下来,使用Visual Studio 2022创建一个Asp.Net Core Web Api项目,我们使用项目中缺省的Web Api进行测试。在项目中增加Identity Server 4对Web Api的保护,这部分的详细介绍参见《Identity Server 4 从入门到落地(十)—— 编写可配置的客户端和Web Api》,这里只列出必要的步骤。
    1、使用Nuget包管理器安装ZL.IdentityServer4ClientConfig和ZL.SameSiteCookiesService
    2、修改Program.cs,增加如下代码:

    ...
    builder.Services.AddIdentityServer4Api(builder.Configuration);//增加代码
    builder.Services.AddSameSiteSupport();;//增加代码
    ...
    app.UseCors("cors");//增加代码
    app.UseAuthentication(); //增加代码
    app.UseAuthorization();
    

    3、在appSettings.json中增加相应的配置:
    "IdentityServer4Api": {
    "Authority": "http://host.docker.internal:4010",
    "CorsOrgins": [
    "http://host.docker.internal:5291"
    ],
    "Policies": [
    {
    "Name": "ApiScope",
    "RequireAuthenticatedUser": "true",
    "Claims": [
    {
    "ClaimType": "scope",
    "AllowValues": [ "testapi" ]
    }
    ]
    }
    ],
    这里定义的认证服务器地址需要根据实际情况进行修改,CorsOrgins中设置的是允许访问的客户端的Uri。这里定义的允许访问的scope是testapi,需要根据实际进行修改。
    4、为Web Api的Action增加[Authorize]标签:

            [Authorize]
            [HttpGet(Name = "GetWeatherForecast")]
            public IEnumerable<WeatherForecast> Get()
            {
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast
                {
                    Date = DateTime.Now.AddDays(index),
                    TemperatureC = Random.Shared.Next(-20, 55),
                    Summary = Summaries[Random.Shared.Next(Summaries.Length)]
                })
                .ToArray();
            }
    

    在认证中心增加Web Api Scope和Swagger Client

    现在我们在认证中心增加Web Api Scope和Swagger Client。
    首先,增加Web Api Scope,在配置文件中定义的允许访问的scope是testapi,所以在这里增加的Scope名称必须为testapi。

    然后,还需要为Swagger 增加一个客户端,名称为demo_api_swagger:

    客户端定义中有几个地方需要注意,首先是允许作用域必须与前面定义的相同,这里是testapi:

    需要客户端密钥设置为false:

    还有重定向的Url,Swagger针对oauth 2.0的重定向地址是swagger/oauth2-redirect.html

    最后,不要忘记在令牌分页中设置CORS:

    修改Swagger相关代码

    在认证中心设置完成后,还需要修改Web Api项目中Swagger相关的代码,使Swagger支持认证。
    首先需要增加一个类,实现IOperationFilter接口:

    using Microsoft.AspNetCore.Authorization;
    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.SwaggerGen;
    
    namespace WebApiIDS4Demo
    {
        public class AuthorizeCheckOperationFilter : IOperationFilter
        {
            public void Apply(OpenApiOperation operation, OperationFilterContext context)
            {
                var hasAuthorize =
                  context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
                  || context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any();
    
                if (hasAuthorize)
                {
                    operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
                    operation.Responses.Add("403", new OpenApiResponse { Description = "Forbidden" });
    
                    operation.Security = new List<OpenApiSecurityRequirement>
                {
                    new OpenApiSecurityRequirement
                    {
                        [
                            new OpenApiSecurityScheme {Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "oauth2"}
                            }
                        ] = new[] {"api1"}
                    }
                };
    
                }
            }
        }
    }
    
    

    然后,在Program.cs中修改Swagger相关的代码:

    ...
    builder.Services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new OpenApiInfo { Title = "Protected API", Version = "v1" });
        var strurl = builder.Configuration["IdentityServer4Api:Authority"];
        options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
        {
            Type = SecuritySchemeType.OAuth2,
            Flows = new OpenApiOAuthFlows
            {
                AuthorizationCode = new OpenApiOAuthFlow
                {
                    AuthorizationUrl = new Uri( strurl +"/connect/authorize"),
                    TokenUrl = new Uri(strurl + "/connect/token"),
                    Scopes = new Dictionary<string, string>
                {
                    {"testapi", "Demo API - full access"}
                }
                }
            }
        });
        options.OperationFilter<AuthorizeCheckOperationFilter>();
    });
    ...
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI(options =>
        {
            options.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            options.OAuthClientId("demo_api_swagger");
            options.OAuthAppName("Demo API - Swagger");
            options.OAuthUsePkce();
        });
    }
    

    改造完成,可以进行测试了,运行Web Api项目,缺省进入Swagger文档页面,我们会发现多了一个Authorize按钮,并且Web Api方法旁边会有一个加锁的图标:

    这时,如果访问Web Api,会出现401错误,我们需要先进行认证再访问,点击加锁的图标,弹出认证界面:

    点击认证按钮,如果顺利的话,会出现认证完成的界面:

    点击Close关闭窗口,会发现加锁图标发生了变化:

    这时,再次访问Web Api就可以正常返回数据了:

     
     
  • 相关阅读:
    java(JDBC连接数据库)[完整版封装]
    java(JDBC连接数据库)[对Statement进行封装]
    HTML基础(DTD & 注释 &常见HTML编码)
    HTML基础(基本结构)
    HTML基础(格式标签)
    java(安全方便的从控制台读入数据)[对Scanner类进行封装,用正则表达式判断]
    java(JDBC连接数据库)[对PreparedStatement进行封装]
    for循环
    什么是操作系统
    字符串内置方法
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/16251703.html
Copyright © 2020-2023  润新知