oauth2和knife4j结合

1.先说knife4j是个什么东西

他是swagger的升级版,在有swagger的调试功能以及接口描述的基础上,让人看着更加一目了然。

这次可能说的比较浅,主要是说怎么使用以及简单配置,还有我自己踩过的坑,因为这个东西我也第一次用。

截个图看看效果

有文档,有调试,可以代替postman了

oauth2和knife4j结合_第1张图片

oauth2和knife4j结合_第2张图片

2. 如何与oauth2权限校验结合

这是重点,我踩了半天坑呢

使用方式有两种,一个是在knife4j通过接口,灵活获取。另一种是通过别的地方获取到token,粘贴到knife4j中。

不管那种方式,token都是作用到全局的

当点击按钮Authorize授权后,如果授权成功,接下来点击其余的接口进行调试时,在请求头会存在参数 Authorization ,如何在未授权之前打开了接口,则需要在授权后关闭该接口的Tab,然后重新打开  

2.1通过别的地方获取到token,粘贴到knife4j中。

oauth2和knife4j结合_第3张图片

oauth2和knife4j结合_第4张图片

 2.1.1 代码实现

package config;

import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

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

/**
 * Kni4j配置类
 *
 * @author haoxr
 * @date 2021-02-25 15:36
 */
@Configuration
@EnableSwagger2WebMvc
@Import(BeanValidatorPluginsConfiguration.class)
@Slf4j
public class SwaggerConfiguration {

    //这个是说swagger功能开启还是关闭,一般来讲生产环境关闭,其他环境开启
    @Value("${swagger.enable}")
    private boolean swaggerEnable;

    @Bean
    public Docket restApi() {
        //schemas
        SecurityContext securityContext = new SecurityContext(Lists.newArrayList(defaultAuth()), PathSelectors.ant("/**"));
        //securityContext
        List securityContexts = Lists.newArrayList(securityContext);
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(swaggerEnable)
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))//所有带@Api注解的类都能扫描到
                .paths(PathSelectors.any())
                .build()
                .securityContexts(securityContexts)
                .securitySchemes(securitySchemes())
                .apiInfo(apiInfo());
    }

    /**
     * 安全模式,这里指定token通过Authorization头请求头传递
     */
    private List securitySchemes() {
        // 设置请求头信息
        List apiKeyList = new ArrayList();
        //请求头里边有Authorization
        apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
        return apiKeyList;
    }

    /**
     * 默认的安全上引用
     */
    private List defaultAuth() {
        //Authorization作用于全局所有接口
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
        return securityReferences;
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("系统管理")
                .description("
测试
") .termsOfServiceUrl("https://www.youlai.tech") .contact(new Contact("测试", "https://gitee.com/youlaiorg", "[email protected]")) .license("Apache-2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0") .version("1.0.0") .build(); } }

2.2在knife4j通过接口,灵活获取

这个官方文档写了四种方式 我用的是第四种 3.19.4 密码模式(password)

3.19 OAuth2 - Knife4j 中文文档 v4.0 - 开发文档 - 文江博客

oauth2和knife4j结合_第5张图片

2.2.1代码实现

package config;

import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

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

/**
 * Kni4j配置类
 */
@Configuration
@EnableSwagger2WebMvc
@Import(BeanValidatorPluginsConfiguration.class)
@Slf4j
public class SwaggerConfiguration {

    //这个就是展示在页面上的url,权限验证所需的url
    @Value("${knife4j.password_token_url}")
    private String passwordTokenUrl;

    @Value("${swagger.enable}")
    private boolean swaggerEnable;

    @Bean
    public Docket restApi() {
        //schema
        List grantTypes = new ArrayList<>();
        //密码模式
        ResourceOwnerPasswordCredentialsGrant resourceOwnerPasswordCredentialsGrant = new ResourceOwnerPasswordCredentialsGrant(passwordTokenUrl);
        grantTypes.add(resourceOwnerPasswordCredentialsGrant);
        OAuth oAuth = new OAuthBuilder().name("oauth2")
                .grantTypes(grantTypes).build();
        //context
        //scope方位
        List scopes = new ArrayList<>();
        scopes.add(new AuthorizationScope("read", "read  resources"));
        scopes.add(new AuthorizationScope("write", "write resources"));
        scopes.add(new AuthorizationScope("reads", "read all resources"));
        scopes.add(new AuthorizationScope("writes", "write all resources"));

        SecurityReference securityReference = new SecurityReference("oauth2", scopes.toArray(new AuthorizationScope[]{}));
        SecurityContext securityContext = new SecurityContext(Lists.newArrayList(securityReference), PathSelectors.ant("/**"));
        //schemas
        List securitySchemes = Lists.newArrayList(oAuth);
        //securityContext
        List securityContexts = Lists.newArrayList(securityContext);
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(swaggerEnable)
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                .paths(PathSelectors.any())
                .build()
                .securityContexts(securityContexts)
                .securitySchemes(securitySchemes)
                .apiInfo(apiInfo());
    }
    
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("系统管理")
                .description("
测试
") .termsOfServiceUrl("https://www.youlai.tech") .contact(new Contact("测试", "https://gitee.com/youlaiorg", "[email protected]")) .license("Apache-2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0") .version("1.0.0") .build(); } }

只能用token接口:这里要注意,如果你用的oauth2,那你就别想着自己加接口了,反正我研究半天,只能用oauth2自带的token接口。不然权限校验那里 principal会为空

而且他对返回的报文结构是有要求的,我们系统之前统一返回的是data包起来的json串,然后我在开始测试knife4j的时候,虽然接口调用成功了,但是各个接口header中的Authorition无法回填,都是undifind。直到我后来去掉外边的那层data,才回填成功

我是怎么处理的:线上正常登录用的是验证码模式。然后knife4j我用的密码模式

在token接口的实现里边,我通过模式区分,如果是验证码模式,就走原来的方法。如果是密码模式,就不做密码解密处理(为了调试方便,knife4j不就是给我们调试用的吗),而且返回的报文体也不被data包着。

oauth2和knife4j结合_第6张图片

3.踩坑记录

不同项目中,虽然可以有互相调用关系,但是swagger配置(knife4j) 需要各写各的。

比如我们项目是网关调用权限系统,在鉴权通过之后,才能继续调用其他的服务系统接口。

然后我们项目在权限系统中有swagger(knife4j),在服务系统中还要配置swagger(knife4j),他们各走各的,互不影响。

oauth2和knife4j结合_第7张图片

 knife4j当然还有其他的配置需要配,但是网上查查应该就可以解决,我这次主要是讲怎么和oauth结合的。

4.访问地址

http://localhost:1234/doc.html

5.代码当中如何配置

@Api(tags = "测试接口")
@RestController
public class SysDataSourceController {


    @ApiOperation("测试下拉选")
    @GetMapping("/type/options")
    public Result> getTypeOptions(){

    }
}

/**
** 请求实体
**/
@ApiModel("数据源搜索")
@Data
public class SourceQuery extends BasePageQuery {

    @ApiModelProperty("关键字(数据源名称/数据源类型 忽略大小写搜索)")
    private String keywords;

    @ApiModelProperty("数据源类型下拉选id,可多选")
    private List sourceTypeIds;

    @ApiModelProperty("创建时间 正序ASC 倒序DESC 默认倒序")
    private OrderEnum orderEnum;
}
    @ApiOperation(value = "详情")
    @GetMapping("/{sourceId}")
    public Result getSourceDetail(
            @ApiParam("数据源ID") @PathVariable Long sourceId
    ) {
       
    }

你可能感兴趣的:(windows)