解决swagger接口每次都要输入JWT Authorization认证的问题

解决swagger接口每次都要输入Authorization认证的问题

原因:每个接口每次调用时都得输入认证参数
目的:统一配置Authorization认证参数,不再需要每个接口都每次输入

在这里插入图片描述

配置示例:

package cn.fc.swagger2;

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * api页面 /swagger-ui.html
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Value("${swagger.enabled}")
    private Boolean enabled;

    @Value("${swagger.host}")
    private String host;

    private static final String SPLITOR = ",";

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(enabled)
                .apiInfo(apiInfo())
                //拼接路径,这个就相当于给swagger测试接口时,在发送的请求地址前增加这个配置的路径,实际根本就不需要,就算项目本身是配了根路径,这里也不需要配置,否则会重复
//                .pathMapping("fcadmin")
                // 必须得配这个,不然默认就是localhost,一但部署到其他服务器上,就会出现测试接口执行时访问路径不对,例如:这个项目就出出现路径是 http://fcadmin/fcadmin/api/device
                .host(host)
                // 选择哪些路径和api会生成document
                .select()
                // 指定只扫描哪些包下面的API生成接口文档,重复写会导致一个都不会扫描
//                .apis(RequestHandlerSelectors.basePackage("cn.fc.modules.bus.device.rest"))
//                .apis(RequestHandlerSelectors.basePackage("cn.fc.modules.system.rest"))
                //调用重写的方法,支持扫描多个包
                .apis(basePackage("cn.fc.modules.bus" + SPLITOR + "cn.fc.modules.system.rest"))
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    /**
     * 重写basePackage方法,让swagger支持多个包扫描
     * @param basePackage
     * @return
     */
    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
    }

    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage)     {
        return input -> {
            // 循环判断匹配
            for (String strPackage : basePackage.split(SPLITOR)) {
                boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                if (isMatch) {
                    return true;
                }
            }
            return false;
        };
    }

    private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
        return Optional.fromNullable(input.declaringClass());
    }

    /**
     * 设置完成后进入SwaggerUI,右上角出现“Authorization”按钮,点击即可输入我们配置的认证参数。
     * 对于不需要输入参数的接口(上文所述的包含auth的接口),在未输入Authorization参数就可以访问。
     * 其他接口则将返回401错误。点击右上角“Authorization”按钮,输入配置的参数后即可通过认证访问。参数输入后全局有效,无需每个接口单独输入。
     * 通过Swagger2的securitySchemes配置全局参数:如下列代码所示,securitySchemes的ApiKey中增加一个名为“Authorization”,type为“header”的参数。
     * @return
     */
    private List<ApiKey> securitySchemes() {
        List<ApiKey> apiKeyList = new ArrayList<>();
        apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
        return apiKeyList;
    }

    /**
     * 在Swagger2的securityContexts中通过正则表达式,设置需要使用参数的接口(或者说,是去除掉不需要使用认证参数的接口),
     * 如下列代码所示,通过PathSelectors.regex("^(?!auth).*$"),所有包含"auth"的接口不需要使用securitySchemes。
     * 即不需要使用上文中设置的名为“Authorization”,type为“header”的认证参数。
     * 通俗讲,就是能匹配上的就使用默认认证,就不使用header里面的Authorization认证参数
     */
    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContexts = new ArrayList<>();
        securityContexts.add(SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("^(?!auth).*$"))
                .build());
        return securityContexts;
    }

    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = {authorizationScope};
        List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
        return securityReferences;
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("fcadmin 接口文档")
                .version("1.0.0")
                .build();
    }

}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,你的问题是关于.Net6.0的跨域解决方案和Swagger的显示问题。针对这个问题,我可以给你提供一些信息。 在.Net6.0中,可以通过使用Jsonp(JSON with Padding)解决跨域问题。Jsonp是一种利用<script>标签的跨域技术,它通过在客户端动态创建<script>标签,将请求发送到跨域服务器,跨域服务器返回包裹在回调函数中的JSON数据,客户端通过执行回调函数来获取数据。Jsonp的优点是兼容性好,支持所有浏览器,但是它的安全性较差,容易受到XSS攻击。 在.Net6.0中,可以通过修改Startup.cs文件中的Configure方法来实现Jsonp的跨域处理。具体代码如下: ```csharp app.Use(async (context, next) => { if (context.Request.Query.ContainsKey("callback")) { context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); context.Response.Headers.Add("Access-Control-Allow-Methods", "GET,POST"); context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type"); context.Response.Headers.Add("Content-Type", "application/javascript"); var callback = context.Request.Query["callback"]; var response = await next.Invoke(); var payload = await response.BodyReader.ReadAsync(); var content = Encoding.UTF8.GetString(payload.Buffer.ToArray()).TrimEnd('\0'); var jsonp = $"{callback}({content})"; var buffer = Encoding.UTF8.GetBytes(jsonp); await context.Response.BodyWriter.WriteAsync(buffer); } else { await next.Invoke(); } }); ``` 针对Swagger的显示问题,可以在Swagger的配置文件中添加跨域相关的配置,具体代码如下: ```csharp services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] {} } }); c.EnableAnnotations(); c.AddFluentValidationRules(); c.OperationFilter<AuthorizeCheckOperationFilter>(); c.OperationFilter<AddHeaderOperationFilter>("Correlation-ID", "Correlation ID for request"); c.OperationFilter<AddResponseHeadersFilter>(); c.OperationFilter<AddSwaggerExamplesHeader>(); c.IncludeXmlComments(XmlCommentsFilePath); c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); c.AddCorsPolicies(); }); ``` 在上面的代码中,c.AddCorsPolicies()方法是自定义的Swagger扩展方法,用来添加跨域相关的配置。具体代码如下: ```csharp public static class SwaggerServiceExtensions { public static void AddCorsPolicies(this SwaggerGenOptions options) { options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = "bearer", BearerFormat = "JWT" }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] {} } }); options.OperationFilter<AuthorizeCheckOperationFilter>(); options.OperationFilter<AddHeaderOperationFilter>("Correlation-ID", "Correlation ID for request"); options.OperationFilter<AddResponseHeadersFilter>(); options.OperationFilter<AddSwaggerExamplesHeader>(); options.IncludeXmlComments(XmlCommentsFilePath); options.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); options.AddCorsPolicies(config => { config.AddPolicy("AllowAll", builder => { builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .WithExposedHeaders("Content-Disposition"); }); }); } public static void AddCorsPolicies(this SwaggerUIOptions options, Action<CorsOptions> setupAction) { var corsOptions = new CorsOptions(); setupAction(corsOptions); options.IndexStream = () => new CorsIndexHtmlStream(corsOptions); } private class CorsIndexHtmlStream : MemoryStream { private readonly CorsOptions _corsOptions; public CorsIndexHtmlStream(CorsOptions corsOptions) { _corsOptions = corsOptions; var basePath = AppContext.BaseDirectory; using (var fileStream = new FileStream(Path.Combine(basePath, "index.html"), FileMode.Open, FileAccess.Read)) { fileStream.CopyToAsync(this).Wait(); } } public override void Write(byte[] buffer, int offset, int count) { var html = Encoding.UTF8.GetString(buffer, offset, count); var corsPolicy = _corsOptions.GetPolicy("AllowAll"); html = html.Replace("__cors_origin__", corsPolicy.AllowAnyOrigin ? "*" : string.Join(",", corsPolicy.Origins)); html = html.Replace("__cors_methods__", string.Join(",", corsPolicy.Methods)); html = html.Replace("__cors_headers__", string.Join(",", corsPolicy.Headers)); buffer = Encoding.UTF8.GetBytes(html); base.Write(buffer, 0, buffer.Length); } } } ``` 在上述代码中,我们主要是通过调用options.AddCorsPolicies()方法来添加跨域相关的配置。这里的跨域配置是基于CORS(Cross-Origin Resource Sharing)实现的,它可以在服务器端控制哪些域名可以访问资源,从而提高安全性。具体的跨域配置可以根据实际需求进行调整。 希望以上信息能够对你有所帮助。如果还有其他问题,请随时提出。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值