美文网首页
Swagger整合Jwt授权配置

Swagger整合Jwt授权配置

作者: 85年的大喇叭 | 来源:发表于2022-03-16 21:16 被阅读0次

    Swagger整合Jwt授权配置

    欢迎关注博主公众号「Java大师」, 专注于分享Java领域干货文章http://www.javaman.cn/sb2/swagger-jwt

    一、Swagger入门

    1、什么是Swagger

    Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务,它有着如下的优点:

    1)及时性 (接口变更后,能够及时准确地通知相关前后端开发人员)

    2)规范性 (并且保证接口的规范性,如接口的地址,请求方式,参数及响应格式和错误信息)

    3)一致性 (接口信息一致,不会出现因开发人员拿到的文档版本不一致,而出现分歧)

    4)可测性 (直接在接口文档上进行测试,以方便理解业务)

    2、Swagger生成文档

    1)添加pom.xml依赖

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="xml" contenteditable="false" cid="n252" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

    <dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
    </dependency>
    <dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
    </dependency></pre>

    2)创建swagger配置文件

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="java" contenteditable="false" cid="n255" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
    @Configuration
    @EnableSwagger2
    public class Swagger2Config {

      @Bean
      public Docket apiConfig() {
          //创建基于Swagger2的配置文件
          return new Docket(DocumentationType.SWAGGER_2)
                  // 调用apiInfo方法,创建一个ApiInfo实例,里面是展示在文档页面信息内容
                  .apiInfo(apiInfo());
      }
      private ApiInfo apiInfo() {
          return new ApiInfoBuilder()
                  //标题
                  .title("接口文档")
                  //描述
                  .description("接口文档")
                  //版本
                  .version("1.0")
                  //作者信息
                  .contact(new Contact("java大师", "http://localhost:8081", "xxx@qq.com"))
                  .build();
      }
    

    }</pre>

    3)启动程序

    访问路径:http://localhost:8081/swagger-ui.html ,出现生成的文档页面。

    image

    此为原生界面,很难看,所以我们需要引入swagger-bootstrap-ui,也就是Knife4j的前身

    4)使用Knife4j

    a)添加pom.xml依赖

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="xml" contenteditable="false" cid="n268" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
    <dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.7</version>
    </dependency></pre>

    b)开启Swagger2配置

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="java" contenteditable="false" cid="n271" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
    import java.util.ArrayList;
    import java.util.List;

    @Configuration
    @EnableSwagger2
    public class Swagger2Config {
    @Bean
    public Docket createRestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
    .pathMapping("/")
    .apiInfo(apiInfo())
    .select()
    //swagger要扫描的包路径
    .apis(RequestHandlerSelectors.basePackage("com.dsblog.server.controller"))
    .paths(PathSelectors.any())
    .build()
    }

      private ApiInfo apiInfo() {
          return new ApiInfoBuilder().title("dsblog接口文档")
                  .contact(new Contact("java大师","http://localhost:8081/doc.html","fry000@qq.com"))
                  .version("1.0").description("dsblog接口文档").build();
      }</pre>
    

    b)重启服务

    访问地址:http://localhost:8081/doc.html,这个ui界面看起来就更美观,更符合国人的使用习惯

    image

    二、Swagger整合Jwt

    1、添加pom.xml依赖

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="xml" contenteditable="false" cid="n282" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
    <?xml version="1.0" encoding="UTF-8"?>

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
      <groupId>com.dsblog</groupId>
      <artifactId>dsblog</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </parent>
    
    <groupId>com.dsblog</groupId>
    <artifactId>dsblog-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
      </dependency>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
      </dependency>
      <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.0</version>
      </dependency>
      <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.31</version>
      </dependency>
      <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.3.2</version>
      </dependency>
      <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-annotations</artifactId>
        <version>1.5.20</version>
      </dependency>
      <!--swagger-->
      <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.7.0</version>
      </dependency>
      <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.7.0</version>
      </dependency>
      <dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
        <version>2.0.7</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>2.3.6.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
      </dependency>
    </dependencies>
    

    </project></pre>

    2、创建Swagger2Config配置文件

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="java" contenteditable="false" cid="n285" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
    package com.dsblog.server.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    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.EnableSwagger2;

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

    @Configuration
    @EnableSwagger2
    public class Swagger2Config {
    @Bean
    public Docket createRestApi() {
    return new Docket(DocumentationType.SWAGGER_2)
    .pathMapping("/")
    .apiInfo(apiInfo())
    .select()
    //swagger要扫描的包路径
    .apis(RequestHandlerSelectors.basePackage("com.dsblog.server.controller"))
    .paths(PathSelectors.any())
    .build()
    .securityContexts(securityContexts())
    .securitySchemes(securitySchemes());
    }

      private ApiInfo apiInfo() {
          return new ApiInfoBuilder().title("dsblog接口文档")
                  .contact(new Contact("java大师","http://localhost:8081/doc.html","fry000@qq.com"))
                  .version("1.0").description("dsblog接口文档").build();
      }
    
      private List<SecurityContext> securityContexts() {
          //设置需要登录认证的路径
          List<SecurityContext> result = new ArrayList<>();
          result.add(getContextByPath("/.*"));
          return result;
      }
    
    //通过pathRegex获取SecurityContext对象
      private SecurityContext getContextByPath(String pathRegex) {
          return SecurityContext.builder()
                  .securityReferences(defaultAuth())
                  .forPaths(PathSelectors.regex(pathRegex))
                  .build();
      }
    
     //默认为全局的SecurityReference对象
      private List<SecurityReference> defaultAuth() {
          List<SecurityReference> result = new ArrayList<>();
          AuthorizationScope authorizationScope = new AuthorizationScope("global",
                  "accessEverything");
          AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
          authorizationScopes[0] = authorizationScope;
          result.add(new SecurityReference("Authorization", authorizationScopes));
          return result;
      }
    
      private List<ApiKey> securitySchemes() {
          //设置请求头信息
          List<ApiKey> result = new ArrayList<>();
          ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
          result.add(apiKey);
          return result;
      }
    

    }</pre>

    3、创建SecurityConfig配置文件

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="java" contenteditable="false" cid="n288" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
    package com.dsblog.server.config.security;

    import com.dsblog.server.model.User;
    import com.dsblog.server.service.IUserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.builders.WebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.http.SessionCreationPolicy;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

      @Autowired
      private IUserService userService;
      @Autowired
      private RestAuthorizationEntryPoint restAuthorizationEntryPoint;
      @Autowired
      private RestAccessDeniedHandler restAccessDeniedHandler;
    
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
          auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
      }
    
     //主要的配置文件,antMatchers匹配的路径,全部忽略,不进行JwtToken的认证
      @Override
      public void configure(WebSecurity web) throws Exception {
          web.ignoring().antMatchers(
                  "/login",
                  "/logout",
                  "/css/**",
                  "/js/**",
                  "/index.html",
                  "favicon.ico",
                  "/doc.html",
                  "/webjars/**",
                  "/swagger-resources/**",
                  "/v2/api-docs/**"
          );
      }
    
      @Override
      protected void configure(HttpSecurity http) throws Exception {
          http.csrf().disable()
                  .sessionManagement()
                  .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                  .and()
                  .authorizeRequests()
                  .anyRequest().authenticated()
                  .and()
                  .headers()
                  .cacheControl();
          //添加Jwt登录授权拦截器
          http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
          //添加未登录和未授权结果返回
          http.exceptionHandling()
                  .accessDeniedHandler(restAccessDeniedHandler)
                  .authenticationEntryPoint(restAuthorizationEntryPoint);
      }
    
      @Override
      @Bean
      public UserDetailsService userDetailsService(){
          return username -> {
              User user = userService.getUserByUsername(username);
              if(null!=user){
                  return user;
              }
              return null;
          };
      }
    
      @Bean
      public PasswordEncoder passwordEncoder(){
          return new BCryptPasswordEncoder();
      }
    
      @Bean
      public  JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
          return new JwtAuthenticationTokenFilter();
      }
    

    }</pre>

    4、创建测试Controller,其中/login登录和/logout退出方法不需要Authorize验证,和上面的重写方法<mark style="box-sizing: border-box; background: rgb(255, 255, 0); color: rgb(0, 0, 0);">configure(WebSecurity web)</mark>匹配,user/info方法需要Authorize验证才能进行访问

    <pre class="md-fences md-end-block md-fences-with-lineno" lang="java" contenteditable="false" cid="n291" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: monospace, monospace; font-size: 0.9em; white-space: pre; display: block; break-inside: avoid; text-align: left; background-image: ; background-position: var(--code-block-bg-color); background-size: ; background-repeat: var(--code-block-bg-color); background-attachment: ; background-origin: ; background-clip: ; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px 0px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
    package com.dsblog.server.controller;

    import com.dsblog.server.model.ResultBean;
    import com.dsblog.server.model.User;
    import com.dsblog.server.model.UserLoginParam;
    import com.dsblog.server.service.IUserService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RestController;

    import javax.servlet.http.HttpServletRequest;
    import java.security.Principal;

    @Api(tags = "LoginController")
    @RestController
    public class LoginController {

      @Autowired
      private IUserService userService;
    
      @ApiOperation("登录")
      @PostMapping("/login")
      public ResultBean login(@RequestBody UserLoginParam userLoginParam, HttpServletRequest request){
          return userService.login(userLoginParam.getUsername(),userLoginParam.getPassword(),request);
      }
    
      @ApiOperation("退出")
      @PostMapping("/logout")
      public ResultBean logout(){
          return ResultBean.success("退出成功!");
      }
    
      @ApiOperation("获取当前登录用户")
      @GetMapping("/user/info")
      public User getUserInfo(Principal principal){
          if(null == principal){
              return null;
          }
          String username = principal.getName();
          User user = userService.getUserByUsername(username);
          user.setPassword(null);
          return user;
      }
    

    }</pre>

    5、重启程序,输入http://localhost:8081/doc.html

    image

    6、测试

    1)首先调用/user/info,会看到提示未登录,请先登录。需要登录授权才能够进行方法的测试 image 2)接着调用登录请求,输入用户名和密码获取JwtToken image 3)获取token后,监测网络,发现会将Authorization放入请求头部发送到后台 image 4)Authorize加入Bearer和JwtToken image

    5)携带token发送到后台获取用户信息,验证通过

    相关文章

      网友评论

          本文标题:Swagger整合Jwt授权配置

          本文链接:https://www.haomeiwen.com/subject/gncmdrtx.html