token-身份令牌的应用,判断用户是否登录

token和session都可以用来做身份验证,而session用多了,对服务器的压力是很大的。
这里主要是生成一个uuid作为账户的身份令牌,用来校验用户是否登录。

项目里有用MyBatis-Plus,先简单说下MyBatis-Plus的配置,如果是用Mybatis之类的可以直接跳过这些配置
maven依赖相应的包

<?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>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.demo</groupId>
    <artifactId>springboottest</artifactId>
    <version>4.0.0</version>
    <name>SpringBootTest</name>
    <description>Demo project for Spring Boot</description>
    <packaging>jar</packaging>

    <properties>
        <java.version>1.8</java.version>
        <logback.version>1.1.3</logback.version>
        <druid.version>1.1.13</druid.version>
        <mybatisplus.version>3.0.7.1</mybatisplus.version>
        <mysql.version>8.0.11</mysql.version>
        <mssql.version>4.0</mssql.version>
        <commons.lang.version>2.6</commons.lang.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>

        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- mssql驱动 -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>sqljdbc4</artifactId>
            <version>${mssql.version}</version>
        </dependency>
        <!-- postgresql驱动 -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>

        <!-- 日志管理 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.6.6</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>${logback.version}</version>
        </dependency>

        <dependency>
            <groupId>org.logback-extensions</groupId>
            <artifactId>logback-ext-spring</artifactId>
            <version>0.1.4</version>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.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>

        <!-- mybatis-plus -->

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatisplus.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>com.baomidou</groupId>
                    <artifactId>mybatis-plus-generator</artifactId>
                </exclusion>
            </exclusions>
        </dependency>



        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>${commons.lang.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件:

server:
  port: 8085
  tomcat:
    uri-encoding: UTF-8
    max-threads: 1000
    min-spare-threads: 30
  servlet:
    context-path: /demo

spring:
    datasource:
      type: com.alibaba.druid.pool.DruidDataSource
      druid:
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&useSSL=false
        username: root
        password: 123456
        initial-size: 10
        max-active: 100
        min-idle: 10
        max-wait: 60000
        pool-prepared-statements: true
        max-pool-prepared-statement-per-connection-size: 20
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 300000
        test-while-idle: true
        test-on-borrow: false
        test-on-return: false
        stat-view-servlet:
          enabled: true
          url-pattern: /druid/*
        filter:
          stat:
            log-slow-sql: true
            slow-sql-millis: 1000
            merge-sql: false
          wall:
            config:
              multi-statement-allow: true

logging:
  level.com.demo: debug
  path: logs/
  file: today.log

mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml
  typeAliasesPackage: com.demo.springboottest.po
  global-config:
    #数据库相关配置
    db-config:
      #主键类型  AUTO:"数据库ID自增", INPUT:"用户输入ID", ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
      id-type: AUTO
      #字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断"
      field-strategy: NOT_NULL
      #驼峰下划线转换
      logic-delete-value: -1
      logic-not-delete-value: 0
    banner: false
    #原生配置
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    call-setters-on-nulls: true
    jdbc-type-for-null: 'null'

mybatis-plus配置

package com.demo.springboottest.config;

import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * mybatis-plus配置
 *
 * @author lk
 */
@Configuration
public class MybatisPlusConfig {

    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }

    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
}

用户 实体类

package com.demo.springboottest.po;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * app端用户表
 * 
 * @author lk
 * @date 2019-05-10 15:40:03
 */
@Data
@TableName("app_user")
public class UserEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 用户id
     */
    @TableId
    private Long userId;
    /**
     * app端用户昵称
     */
    private String userName;
    /**
     * 电话号码
     */
    private String mobile;
    /**
     * 登录密码
     */
    private String password;
    /**
     * app用户编号
     */
    private String userCode;
    /**
     * 用户性别0:男 1:女
     */
    private Integer userSex;
    /**
     * 用户邮箱
     */
    private String userEmail;
    /**
     * 用户头像url
     */
    private String userHeadImage;
    /**
     * 省
     */
    private String userProvince;
    /**
     * 市
     */
    private String userCity;
    /**
     * 区
     */
    private String userArea;
    /**
     * 身份证号
     */
    private String userCertId;
    /**
     * 证件类型(默认1身份证)
     */
    private Integer userCertType;
    /**
     * 详细地址
     */
    private String userAddress;
    /**
     * 生日
     */
    private Date userBirthday;
    /**
     * 用户状态1:正常  0失效 
     */
    private Integer userState;
    /**
     * 创建时间 
     */
    private Date createTime;
    /**
     * 修改时间
     */
    private Date updateTime;

}

用户Token

package com.demo.springboottest.po;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * 用户Token
 * 
 * @author lk
 * @email
 * @date 2019-03-26 10:29:14
 */
@Data
@TableName("app_token")
public class TokenEntity implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 
     */
    @TableId(type = IdType.INPUT)
    private Long userId;
    /**
     * token
     */
    private String token;
    /**
     * 过期时间
     */
    private Date expireTime;
    /**
     * 更新时间
     */
    private Date updateTime;

}

@Data 是lombok插件的注解,自动生成get、set、toString等
注意如果用了MyBatis-Plus创建的实体类必须加@TableName注解,否则会报错,当然你也得去建相应的表


image.png

image.png

配置一个自定以注解:@Login, 只要加了这个注解的就会校验用户的Token。

package com.demo.springboottest.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
}

@LoginUser 用来获取用户信息,需要的话可以配置,也可以忽视的。

package com.demo.springboottest.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 登录用户信息
 *
 * @author lk
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {

}

用户登录的时候给当前用户生成或修改token
controller

package com.demo.springboottest.controller;

import com.demo.springboottest.annotation.Login;
import com.demo.springboottest.annotation.LoginUser;
import com.demo.springboottest.ao.LoginAO;
import com.demo.springboottest.exception.RRException;
import com.demo.springboottest.po.UserEntity;
import com.demo.springboottest.service.TokenService;
import com.demo.springboottest.service.UserService;
import com.demo.springboottest.util.ReturnResult;
import com.demo.springboottest.util.ValidatorUtils;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import java.util.Map;

/**
 * @author lk
 */
@Api(tags = "登录接口")
@RestController
@RequestMapping("/user")
public class LoginController {
    private Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Resource
    private UserService userService;

    @Resource
    private TokenService tokenService;

    @PostMapping("login")
    @ApiOperation(value = "登录", notes = "用户登录成功,返回token和token失效时间")
    @ApiImplicitParam(name = "loginAO", value = "用户登录参数", required = true, paramType = "body", dataType = "LoginAO")
    public ReturnResult login(@RequestBody LoginAO loginAO) {
        Map<String, Object> result;
        logger.info("method : login(),params: " + loginAO.toString());
        try {
            //校验参数
            ValidatorUtils.validateEntity(loginAO);
            result = userService.login(loginAO);
        } catch (RRException rre) {
            //返回自定义异常
            logger.error(rre.getMsg());
            return ReturnResult.error(rre.getMsg());
        }
        return ReturnResult.ok(result);
    }


    @Login
    @PostMapping("logout")
    @ApiOperation(value = "登出", notes = "将该用户的token失效期设置为当前时间")
    public ReturnResult logout(@ApiIgnore @RequestAttribute("userId") long userId) {
        tokenService.expireToken(userId);
        return ReturnResult.ok();
    }

    @Login
    @GetMapping("userInfo")
    @ApiOperation(value = "查询", notes = "获取用户信息")
    public ReturnResult getUser(@ApiIgnore @LoginUser UserEntity userEntity) {
        return ReturnResult.ok().put("user", userEntity);
    }
}

service

package com.demo.springboottest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.springboottest.ao.LoginAO;
import com.demo.springboottest.dao.UserMapper;
import com.demo.springboottest.exception.RRException;
import com.demo.springboottest.po.TokenEntity;
import com.demo.springboottest.po.UserEntity;
import com.demo.springboottest.service.TokenService;
import com.demo.springboottest.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity> implements UserService {

    @Resource
    private TokenService tokenService;

    @Override
    public Map<String, Object> login(LoginAO loginAO) {
        Map<String, Object> result = new HashMap<>(2);
        String mobile = loginAO.getMobile();
        UserEntity user = queryUser(mobile);
        if (null != user) {
            if (!user.getPassword().equals(loginAO.getPassword())) {
                throw new RRException("密码错误!");
            }
        }else {
            throw new RRException("该账户不存在!");
        }


        //获取登录token
        TokenEntity tokenEntity = tokenService.createToken(user.getUserId());
        result.put("token", tokenEntity.getToken());
        result.put("expire", tokenEntity.getExpireTime().getTime() - System.currentTimeMillis());
        return result;
    }

    private UserEntity queryUser(String mobile) {
        return baseMapper.selectOne(new QueryWrapper<UserEntity>().eq("mobile", mobile));
    }
}

生成token createToken(long id),登出的时候调expireToken(long userId) 使当前用户的token失效时间设置为当前时间

package com.demo.springboottest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.springboottest.dao.TokenMapper;
import com.demo.springboottest.po.TokenEntity;
import com.demo.springboottest.service.TokenService;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.UUID;

@Service
public class TokenServiceImpl extends ServiceImpl<TokenMapper, TokenEntity> implements TokenService {

    /**
     * 12小时后过期
     */
    private final static int EXPIRE = 3600 * 12;

    @Override
    public TokenEntity createToken(long id) {
        //当前时间
        Date now = new Date();
        //过期时间
        Date expireTime = new Date(now.getTime() + EXPIRE * 1000);

        //生成token
        String token = UUID.randomUUID().toString().replace("-", "");

        //保存或更新用户token
        TokenEntity tokenEntity = new TokenEntity();
        tokenEntity.setUserId(id);
        tokenEntity.setToken(token);
        tokenEntity.setUpdateTime(now);
        tokenEntity.setExpireTime(expireTime);
        saveOrUpdate(tokenEntity);

        return tokenEntity;
    }

    @Override
    public void expireToken(long userId) {
        Date now = new Date();

        TokenEntity tokenEntity = new TokenEntity();
        tokenEntity.setUserId(userId);
        tokenEntity.setUpdateTime(now);
        tokenEntity.setExpireTime(now);

        saveOrUpdate(tokenEntity);
    }

    @Override
    public TokenEntity queryByToken(String token) {
        return getOne(new QueryWrapper<TokenEntity>().eq("token", token));
    }
}

当然还需要配置一个拦截器,拦截只要加了@Login注解的方法就会校验用户的token
拦截器:

package com.demo.springboottest.interceptor;

import com.demo.springboottest.annotation.Login;
import com.demo.springboottest.exception.RRException;
import com.demo.springboottest.po.TokenEntity;
import com.demo.springboottest.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author LK
 */

@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private TokenService tokenService;

    public static final String USER_KEY = "userId";


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Login annotation;
        if(handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(Login.class);
        }else{
            return true;
        }

        if(annotation == null){
            return true;
        }

        //从header中获取token
        String token = request.getHeader("token");
        //如果header中不存在token,则从参数中获取token
        if(StringUtils.isBlank(token)){
            token = request.getParameter("token");
        }

        //token为空
        if(StringUtils.isBlank(token)){
            throw new RRException(403,"token不能为空");
        }

        //查询token信息
        TokenEntity tokenEntity = tokenService.queryByToken(token);
        if (null != tokenEntity && StringUtils.isNotBlank(tokenEntity.toString())) {
            //token失效
            if (tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) {
                throw new RRException(401,"请重新登录");
            }
        } else {
            throw new RRException(402,"该用户或已重新登录");
        }
        //设置userId到request里,后续根据userId,获取用户信息
        request.setAttribute(USER_KEY, tokenEntity.getUserId());
        return true;
    }

}

@LoginUser 获取用户信息



package com.demo.springboottest.resolver;

import com.demo.springboottest.annotation.LoginUser;
import com.demo.springboottest.interceptor.AuthorizationInterceptor;
import com.demo.springboottest.po.UserEntity;
import com.demo.springboottest.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * 有@LoginUser注解的方法参数,注入当前登录用户
 *
 * @author lk
 */
@Component
public class LoginUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    @Autowired
    private UserService userService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().isAssignableFrom(UserEntity.class) && parameter.hasParameterAnnotation(LoginUser.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container,
                                  NativeWebRequest request, WebDataBinderFactory factory) throws Exception {
        //获取用户ID
        Object object = request.getAttribute(AuthorizationInterceptor.USER_KEY, RequestAttributes.SCOPE_REQUEST);
        if (object == null) {
            return null;
        }


        //获取用户信息
        return userService.getById((Long) object);
    }
}

WebMvcConfigurer

package com.demo.springboottest.config;

import com.demo.springboottest.interceptor.AuthorizationInterceptor;
import com.demo.springboottest.resolver.LoginUserHandlerMethodArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

/**
 * MVC配置
 *
 * @author lk
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private AuthorizationInterceptor authorizationInterceptor;
    @Autowired
    private LoginUserHandlerMethodArgumentResolver loginUserHandlerMethodArgumentResolver;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authorizationInterceptor).addPathPatterns("/**");
    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(loginUserHandlerMethodArgumentResolver);
    }
}

需要注意的是/** 不可以设置为/demo/** ,/demo 为context-path 否则会使拦截器失效


image.png

异常处理器



package com.demo.springboottest.util;

import com.demo.springboottest.exception.RRException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 异常处理器
 *
 * @author lk
 */
@RestControllerAdvice
public class RRExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(getClass());

    /**
     * 处理自定义异常
     */
    @ExceptionHandler(RRException.class)
    public ReturnResult handleRRException(RRException e){
        ReturnResult r = new ReturnResult();
        r.put("code", e.getCode());
        r.put("msg", e.getMessage());

        return r;
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public ReturnResult handleDuplicateKeyException(DuplicateKeyException e){
        logger.error(e.getMessage(), e);
        return ReturnResult.error("数据库中已存在该记录");
    }

    @ExceptionHandler(Exception.class)
    public ReturnResult handleException(Exception e){
        logger.error(e.getMessage(), e);
        return ReturnResult.error();
    }
}

在swagger配置里添加securitySchemes 可以在swagger页面设置header


image.png


package com.demo.springboottest.config;

import io.swagger.annotations.ApiOperation;
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.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.List;

import static com.google.common.collect.Lists.newArrayList;

/**
 * Swagger配置
 *
 * @author lk
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .select()
            //加了ApiOperation注解的类,生成接口文档
            .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
            //包下的类,生成接口文档
            .paths(PathSelectors.any())
            .build()
                .securitySchemes(security());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("swagger")
            .description("spring boot swagger test")
            .termsOfServiceUrl("localhost:8085/demo")
            .version("4.0.0")
            .build();
    }

    private List<ApiKey> security() {
        return newArrayList(
                new ApiKey("token", "token", "header")
        );
    }


}

访问接口没有设置token的时候


image.png

获取token


image.png

将其复制粘贴到


image.png

设置token后访问接口
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,423评论 0 4
  • 对于java中的思考的方向,1必须要看前端的页面,对于前端的页面基本的逻辑,如果能理解最好,不理解也要知道几点。 ...
    神尤鲁道夫阅读 802评论 0 0
  • 1、什么是框架? 框架就是一组程序的集合,本质上是一组jar包的集合,jar包中存有class文件或一些资源文件。...
    Yulin_ZH阅读 950评论 1 1
  • MyBatis 理论篇 [TOC] 什么是MyBatis  MyBatis是支持普通SQL查询,存储过程和高级映射...
    有_味阅读 2,881评论 0 26
  • (原创作品) 深夜无眠 呆在阳台 看那厚厚的云 盖住了所有的星星 没有一点点光 漆黑的夜 犹如我的心 想着那个人 ...
    金源宏阅读 298评论 0 3