SpringBoot集成Swagger2登录功能和安全认证

news2025/1/18 18:14:03

本篇文章要实现的功能:

  • 1.集成swagger
  • 2.集成swagger登录功能,访问 /swagger-ui.html需要先登录
  • 3.集成安全认证,访问接口时携带header

在这里插入图片描述


请求接口时携带了上一步输入的header参数和值
在这里插入图片描述

1.集成swagger

jdk11,SpringBoot 2.7.13
pom.xml依赖swagger2.10.5

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.10.5</version>
</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.10.5</version>
</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-spring-webmvc</artifactId>
	<version>2.10.5</version>
</dependency>

application.yml

swagger:
  enable: true   #是否开启swagger
  basic:
    enable: true  #是否开启登录认证
    username: admin
    password: admin
2.集成swagger登录功能,访问 /swagger-ui.html需要先登录

新建 Swagger2Config

import com.zypcy.mono.interceptor.SwaggerInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.MappedInterceptor;
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.Docket;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

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

@Configuration
@EnableWebMvc
@EnableSwagger2WebMvc
@ConditionalOnProperty(
        name = {"swagger.enable"},
        havingValue = "true",
        matchIfMissing = false
)
public class Swagger2Config implements WebMvcConfigurer {

    @Value("${spring.profiles.active}")
    private String active;
    @Value("${swagger.basic.username:admin}")
    private String username;
    @Value("${swagger.basic.password:admin}")
    private String password;

    private String basePackage = "com.zypcy.mono.controller";

    /**
     * 开放swagger-ui.html资源
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }

    /* 在此处配置拦截器,要不然拦不到swagger的静态资源 */
    @Bean
    @ConditionalOnProperty(name = "swagger.basic.enable", havingValue = "true")
    public MappedInterceptor getMappedInterceptor() {
        return new MappedInterceptor(new String[]{"/swagger-ui.html", "/v2/api-docs", "/webjars/**"}, new SwaggerInterceptor(username, password));
    }

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(!"prod".equals(active))
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(basePackage))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Mono API 接口文档")
                .description("Mono REST API 接口文档")
                .termsOfServiceUrl("")
                .contact(new Contact("zhuyu", "https://zhuyu.blog.csdn.net", "645906265@qq.com"))
                .license("Mono License Version 2.0")
                .licenseUrl("http://www.xxx.xxx/licenses/LICENSE-2.0")
                .version("1.0")
                .build();
    }

    //3.集成安全认证,访问接口时携带header
    private List<SecurityScheme> securitySchemes() {
        List<SecurityScheme> res = new ArrayList<>();
        res.add(new ApiKey("AppId", "AppId", "header"));
        res.add(new ApiKey("Authorization", "Authorization", "header"));
        return res;
    }

    private List<SecurityContext> securityContexts() {
        List<SecurityContext> res = new ArrayList<>();
        res.add(SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex("/.*"))
                .build());
        return res;
    }

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

    /**
     * 添加header,调用代码:this.header("x-request-info", "string", false, "appId=101;token=a256f4c4f38a76115355d2d039e2882e;")
     * @param name
     * @param type
     * @param required
     * @param defaultValue
     * @return
     */
    private Parameter header(String name, String type, boolean required, String defaultValue) {
        ParameterBuilder param = new ParameterBuilder();
        return param.name(name).modelRef(new ModelRef(type)).parameterType("header").defaultValue(defaultValue).required(required).build();
    }

}

创建拦截器 SwaggerInterceptor

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Base64;

/**
 * @Description:
 * @Author: zhuyu
 * @Date: 2023/11/22 20:44
 */
public class SwaggerInterceptor implements HandlerInterceptor {
    private String username;
    private String password;
    public SwaggerInterceptor(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String authorization = request.getHeader("Authorization");
        boolean isAuthSuccess = httpBasicAuth(authorization);
        if (!isAuthSuccess) {
            response.setCharacterEncoding("utf-8");
            response.setStatus(401);
            response.setHeader("WWW-authenticate", "Basic realm=\"Realm\"");
            try (PrintWriter writer = response.getWriter()) {
                writer.print("Forbidden, unauthorized user");
            }
        }
        return isAuthSuccess;
    }
    public boolean httpBasicAuth(String authorization) throws IOException {
        if (authorization != null && authorization.split(" ").length == 2) {
            String userAndPass = new String(Base64.getDecoder().decode((authorization.split(" ")[1])));
            String username = userAndPass.split(":").length == 2 ? userAndPass.split(":")[0] : null;
            String password = userAndPass.split(":").length == 2 ? userAndPass.split(":")[1] : null;
            if (this.username.equals(username) && this.password.equals(password)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String uri = request.getRequestURI();
        AntPathMatcher pathMatcher = new AntPathMatcher();
        if (!pathMatcher.match("/swagger-ui.html", uri) && !pathMatcher.match("/webjars/**", uri)) {
            response.setStatus(404);
            return;
        }
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        Resource[] resources = resolver.getResources("classpath:/META-INF/resources" + uri);
        if (resources != null && resources.length > 0) {
            FileCopyUtils.copy(resources[0].getInputStream(), response.getOutputStream());
        } else {
            response.setStatus(404);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1239239.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis运维(十四) hash缓存案例

一 缓存案例 ① 需求 ② 个人理解 策略&#xff1a;不更新缓存&#xff0c;而是删除缓存大部分观点认为&#xff1a;1、做缓存不应该是去更新缓存,而是应该删除缓存2、然后由下个请求去缓存,发现不存在后再读取数据库,写入redis缓存 高并发场景下,到底先更新缓存还是先更…

Android studio 迁移之后打开没反应

把Android studio由d盘迁移到c盘&#xff0c;点击没反应&#xff1b; 需要把C:\Users\xxxx\AppData\Roaming\Google\AndroidStudio2022.3 目录下的studio64.exe.vmoptions 修改为C:&#xff0c;删除该文件会导致无法安装app。 里面配置了一个

git常用命令(git github ssh)

目录 1、语法说明2、本地仓库相关操作建立一个git文件(git init)把工作区的文件添加到暂存区(git add)把暂存区的文件添加到本地仓库(git commit)查看暂存区和本地仓库中的文件(git ls-files)查看文件夹下所有文件的状态(git status)查看版本库中的提交记录(git log)恢复的文件…

Linux系统管理与服务器安全:构建稳健云数据中心

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 在当今数字化时代&#xff0c;云数据中心已经成…

Program Header Table(转载)

程序头表与段表相互独立&#xff0c;由ELF文件头统一管理。 程序头表负责ELF文件从文件到加载后映像的映射关系&#xff0c;一般只有可执行文件包含。 1. segment和section segment: 程序头表项描述的对象称为segment&#xff0c;即elf文件加载后的数据块&#xff1b; 它提供…

【计算方法与科学建模】矩阵特征值与特征向量的计算(二):Jacobi 过关法及其Python实现(Jacobi 旋转法的改进)

文章目录 一、Jacobi 旋转法1. 基本思想2. 注意事项 二、Jacobi 过关法1. 基本思想2. 注意事项 三、Python实现迭代过程&#xff08;调试&#xff09; 矩阵的特征值&#xff08;eigenvalue&#xff09;和特征向量&#xff08;eigenvector&#xff09;在很多应用中都具有重要的数…

2023.11.22 homework

七年级数学 五年级数学 也不知道可以教到几年级&#xff0c;估计很快就教不动了。人生啊。

地图导航测试用例,你get了吗?

地图导航是我们经常使用的工具&#xff0c;能帮助我们指引前进的方向。 接下来&#xff0c;会从功能测试、UI测试、兼容测试、安全测试、网络测试、性能测试、易用性测试、文档和国际化语言测试8个方面来编写地图导航测试用例。 一 功能测试 输入起点和终点&#xff0c;验证…

五大资源之Service(可以固定IP)

Service可以看作是一组同类Pod对外访问接口,借助Service应用可以方便的实现服务发现与负载均衡 创建集群内部可以访问Service #暴露Service(也创建在了namespace dev下) [root@master ~]# kubectl expose deployment(pod控制器) nginx --name=svc-nginx1 --type=Cluste…

实在智能携“TARS大模型”入选“2023中国数据智能产业AI大模型先锋企业”

近日&#xff0c;由数据猿与上海大数据联盟联合主办的“2023企业数智化转型升级发展论坛”在上海圆满收官。 论坛颁奖典礼上&#xff0c;《2023中国数据智能产业AI大模型先锋企业》等六大榜单正式揭晓&#xff0c;旨在表彰在AI领域为数智化升级取得卓越成就和突出贡献的企业&am…

最新PHP熊猫头图片表情斗图生成源码

这是一款能生成熊猫头表情斗图的自适应系统源码&#xff0c;无论是在电脑还是手机上都可以正常使用&#xff01;这个源码集成了搜狗搜索图片接口&#xff0c;可以轻松地一键搜索数百万张图片&#xff0c;并且还包含了表情制作等功能模块。对于一些新站来说&#xff0c;这是一个…

代码规范之-理解ESLint、Prettier、EditorConfig

前言 团队多人协同开发项目&#xff0c;困扰团队管理的一个很大的问题就是&#xff1a;无可避免地会出现每个开发者编码习惯不同、代码风格迥异&#xff0c;为了代码高可用、可维护性&#xff0c;需要从项目管理上尽量统一和规范代码。理想的方式需要在项目工程化方面&#xff…

元素清空操作clear与选择操作check

元素清空操作clear与选择操作check clear() 作用 清空输入框的所有内容.clear() 等价于 .type("{selectall}{backspace}") 语法 .clear() .clear(options)option选项 元素选中操作check与uncheck check 语法 // 所有匹配到的选择框都会被选中一遍 .check()/…

【HarmonyOS】元服务卡片本地启动拉起加桌没问题,上架后拉起加桌时卡片展示异常

【关键字】 加桌选卡展示异常 、 2卡共用一个布局 、 代码混淆 【问题现象】 元服务卡片在本地启动拉起加桌时&#xff0c;多卡的选卡过程显示是没问题的。但是在上架后拉起加桌时&#xff0c;多卡的选卡过程卡片展示异常。 代码逻辑是通过创建卡片的时候判断卡片的尺寸大小…

Web前端—移动Web第四天(vw适配方案、vw和vh的基本使用、综合案例-酷我音乐)

版本说明 当前版本号[20231122]。 版本修改说明20231122初版 目录 文章目录 版本说明目录移动 Web 第四天01-vw适配方案vw和vh基本使用vw布局vh布局混用问题 02-综合案例-酷我音乐准备工作头部布局头部内容搜索区域banner 区域标题公共样式排行榜内容推荐歌单布局推荐歌单内…

生活如果真能像队列一样的话

生活如果真能像队列一样&#xff0c;那该多好啊。 —————————————————————————————————————————— 背包&#xff0c;队列 可以先看他们的API&#xff1a;都含有一个无参构造函数&#xff0c;添加单个元素的方法&#xff0c;测试集合…

自动化测试 —— 元素定位

1.什么是自动化测试 自动化测试的概念:软件自动化测试就是通过测试工具或者其他手段&#xff0c;按照测试人员的预定计划对软件产品进行自动化测试&#xff0c;他是软件测试的一个重要组成部分&#xff0c;能够完成许多手工测试无法完成或者难以实现的测试工作&#xff0c;正确…

带记忆的超级GPT智能体,能做饭、煮咖啡、整理家务!

随着AI技术的快速迭代&#xff0c;Alexa、Siri、小度、天猫精灵等语音助手得到了广泛应用。但在自然语言理解和完成复杂任务方面仍然有限。 相比文本的标准格式&#xff0c;语音充满复杂性和多样性&#xff08;例如&#xff0c;地方话&#xff09;,传统方法很难适应不同用户的…

【C++初阶】STL详解(五)List的介绍与使用

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…