spring boot:swagger3的安全配置(swagger 3.0.0 / spring security / spring boot 2.3.3)
一,swagger有哪些环节需要注意安全?
1,生产环境中,要关闭swagger
application.properties中配置:
springfox.documentation.swagger-ui.enabled=false
2,swagger使用一台专用的服务器来部署,
可以访问的ip地址要做限制,
外部的防火墙和应用中都做限制,
3,自定义访问swagger的url
4, 可以访问swagger的用户要做权限的验证
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/25/springbootswagger3-de-an-quan-pei-zhi-swagger300springsecurityspringboot233/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,演示项目的相关信息
1,项目地址
https://github.com/liuhongdi/swagger3security
2,项目功能说明:
演示了swagger3的安全配置
3,项目结构:如图:
三,配置文件说明
1,pom.xml
<!-- swagger3 begin --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> <!-- spring security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
2,application.properties
#error server.error.include-stacktrace=always #error logging.level.org.springframework.web=trace #swagger,使可用 springfox.documentation.swagger-ui.enabled=true #改变url springfox.documentation.swagger-ui.base-url=/lhddoc #设置允许访问的ip地址白名单 swagger.access.iplist = 192.168.3.1,127.0.0.1
四,java代码说明
1,Swagger3Config.java
@EnableOpenApi @Configuration public class Swagger3Config implements WebMvcConfigurer { @Bean public Docket createRestApi() { //返回文档摘要信息 return new Docket(DocumentationType.OAS_30) .apiInfo(apiInfo()) .select() //.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .apis(RequestHandlerSelectors.withMethodAnnotation(Operation.class)) .paths(PathSelectors.any()) .build() .globalRequestParameters(getGlobalRequestParameters()) .globalResponses(HttpMethod.GET, getGlobalResonseMessage()) .globalResponses(HttpMethod.POST, getGlobalResonseMessage()); } //生成接口信息,包括标题、联系人等 private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Swagger3接口文档") .description("如有疑问,请联系开发工程师老刘。") .contact(new Contact("刘宏缔", "https://www.cnblogs.com/architectforest/", "371125307@qq.com")) .version("1.0") .build(); } //生成全局通用参数 private List<RequestParameter> getGlobalRequestParameters() { List<RequestParameter> parameters = new ArrayList<>(); parameters.add(new RequestParameterBuilder() .name("appid") .description("平台id") .required(true) .in(ParameterType.QUERY) .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING))) .required(false) .build()); parameters.add(new RequestParameterBuilder() .name("udid") .description("设备的唯一id") .required(true) .in(ParameterType.QUERY) .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING))) .required(false) .build()); parameters.add(new RequestParameterBuilder() .name("version") .description("客户端的版本号") .required(true) .in(ParameterType.QUERY) .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING))) .required(false) .build()); return parameters; } //生成通用响应信息 private List<Response> getGlobalResonseMessage() { List<Response> responseList = new ArrayList<>(); responseList.add(new ResponseBuilder().code("404").description("找不到资源").build()); return responseList; } }
配置swagger3
2,HomeController.java
@Api(tags = "首页信息管理") @Controller @RequestMapping("/home") public class HomeController { @Operation(summary = "session详情") @GetMapping("/session") @ResponseBody public String session() { HttpSession session = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getSession(); Enumeration e = session.getAttributeNames(); String s = ""; while( e.hasMoreElements()) { String sessionName=(String)e.nextElement(); s += "name="+sessionName+";<br/>"; s += "value="+session.getAttribute(sessionName)+";"; } return s; } }
查看当前登录用户的session
3,SecurityConfig.java
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Value("${swagger.access.iplist}") private String iplist; @Override protected void configure(HttpSecurity http) throws Exception { //得到iplist列表 String iprule = ""; //hasIpAddress('10.0.0.0/16') or hasIpAddress('127.0.0.1/32') String[] splitAddress=iplist.split(","); for(String ip : splitAddress){ if (iprule.equals("")) { iprule = "hasIpAddress('"+ip+"')"; } else { iprule += " or hasIpAddress('"+ip+"')"; } } String swaggerrule = "hasAnyRole('ADMIN','DEV') and ("+iprule+")"; //login和logout http.formLogin() .defaultSuccessUrl("/home/session") .failureUrl("/login-error.html") .permitAll() .and() .logout(); //匹配的页面,符合限制才可访问 http.authorizeRequests() //.antMatchers("/actuator/**").hasIpAddress("127.0.0.1") //.antMatchers("/admin/**").access("hasRole('admin') and (hasIpAddress('127.0.0.1') or
//hasIpAddress('192.168.1.0/24') or hasIpAddress('0:0:0:0:0:0:0:1'))"); .antMatchers("/lhddoc/**").access(swaggerrule) .antMatchers("/goods/**").hasAnyRole("ADMIN","DEV"); //剩下的页面,允许访问 http.authorizeRequests().anyRequest().permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { //添加两个账号用来做测试 auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()) .withUser("lhdadmin") .password(new BCryptPasswordEncoder().encode("123456")) .roles("ADMIN","USER") .and() .withUser("lhduser") .password(new BCryptPasswordEncoder().encode("123456")) .roles("USER"); } }
spring security的配置,重点是ip地址白名单的限制要加入
4,Goods.java等,可以从github.com查看
五,测试效果
1,无权限的访问效果:
用lhduser账号登录
从session页面可以看到当前登录用户的授权角色是:ROLE_USER
因为没有权限,访问swagger时会报错
2,有权限访问时的效果:
用lhdadmin登录
查看session:
可以看到用户权限包括:ROLE_ADMIN
访问swagger:
http://127.0.0.1:8080/lhddoc/swagger-ui/
返回:
3,从非授权的ip地址访问:
既使用获得授权的用户账号登录也会报错,因为ip未授权
六,查看spring boot的版本
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.3.RELEASE)