Swagger2,JWT使用

1 SSM整合Swagger2

1.1 介绍

Swagger是一套围绕OpenAPI规范构建的开源工具,可以帮助您设计,构建,记录和使用REST API。
swagger 能够根据代码中的注释自动生成 api 文档,并且提供测试接口。

1.2 用法

  1. 引入依赖
<!-- swagger2-->
    <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>
  1. 配置类SwaggerConfig.java
    @Bean:交给spring管理
    Docket:swagger2的核心对象
@Configuration
@EnableWebMvc
@EnableSwagger2
public class SwaggerConfig {
    @Bean   // 交给Spring管理
    public Docket docket() {
        // swagger2的核心对象
        Docket docket = new Docket(DocumentationType.SWAGGER_2);
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("Java201 Api[接口文档]")
                .description("项目1组文档")
                .contact(new Contact("lxy","www.baidu.com","[email protected]"))
                .version("1.0")
                .build();
        /**
         * 配置docket
         */
        docket.apiInfo(apiInfo)
                .select()
                // 配置类上面有@Api这个注解会被扫描到
                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                // 配置方法上有@ApiOperation这个注解会被扫描到
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                //任何路径
                .paths(PathSelectors.any())  
                .build();
        return docket;
    }
}
  1. spring-web.xml中配置
    在这里插入图片描述
  2. 测试
    过滤器放开路径/swagger-ui.html
    controller下写个测试 SwaggerController:
@Controller
@Api(tags = "API测试",value = "测试类")
public class SwaggerController {
    @GetMapping("/swagger/test")
    @ResponseBody
    @ApiOperation(tags = "测试方法",value = "xxxxxx")
    @ApiImplicitParam(paramType = "query",name = "id",value = "数据id",required = true,dataType = "int")
    public JsonResult test(Integer id){
        return new JsonResult(200,"success",id);
    }
    @GetMapping("/swagger/test2")
    @ResponseBody
    @ApiOperation(tags = "测试方法2",value = "ooooo")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query",name = "id",value = "数据id",required = true,dataType = "int"),
            @ApiImplicitParam(paramType = "query",name = "name",value = "名字",required = true,dataType = "string"),
    })
    public JsonResult test2(Integer id,String name){
        return new JsonResult(200,"success",id+":"+name);
    }
}

在这里插入图片描述
在这里插入图片描述

1.3 注解解释

@ApiImplicitParam参数:
在这里插入图片描述

2 JWT

2.1 简介

前后端完全分离:
找不到session
在这里插入图片描述
Json Web Token,是一种工具。格式为XXXX.XXXX.XXXX的字符串,以一种安全的方式在用户和服务器之间传递存放在JWT中的不敏感信息

用户第二次不需要再次进行登陆操作,通过JWT可实现用户认证的功能。使用session,但会增加服务器存储压力,JWT将存储压力分布到各个客户端机器上,从而减轻服务器压力。

2.2 JWT的格式

由三个字符串组成:Header.Payload.Signature(Claim是描述Json的信息的一个Json,将Claim转码之后生成Payload)

Header 是由以下这个格式的 Json 通过 Base64 编码(编码不是加密,是可以通过反编码的方式获取到这个原来的 Json,所以 JWT 中存放的一般是不敏感的信息)生成的字符串,Header 中存放的内容是说明编码对象是一个 JWT 以及使用“SHA-256”的算法进行加密(加密用于生成 Signature)

Claim 是一个 Json,Claim 中存放的内容是 JWT 自身的标准属性,所有的标准属性都是可选的,可以自行添加,比如:JWT 的签发者、JWT 的接收者、JWT 的持续时间等;同时Claim 中也可以存放一些自定义的属性,这个自定义的属性就是在用户认证中用于标明用户身份的一个属性,比如用户存放在数据库中的 id,为了安全起见,一般不会将用户名及密码这类敏感的信息存放在 Claim 中。将 Claim 通过 Base64 转码之后生成的一串字符串称作 Payload。
在这里插入图片描述
Signature 是由 Header 和 Payload 组合而成,将 Header 和 Claim 这两个 Json 分别使用Base64 方式进行编码,生成字符串 Header 和 Payload,然后将 Header 和 Payload 以Header.Payload 的格式组合在一起形成一个字符串,然后使用上面定义好的加密算法和一个密匙(这个密匙存放在服务器上,用于进行验证)对这个字符串进行加密,形成一个新的字符串,这个字符串就是 Signature。

JWT大致流程:
在这里插入图片描述

2.3 认证原理

服务器在生成一个 JWT 之后会将这个 JWT 会以Authorization : Bearer JWT 键值对的形式存放在 cookies 里面发送到客户端机器,在客户端再次访问收到 JWT 保护的资源 URL 链接的时候,服务器会获取到 cookies 中存放的 JWT 信息,首先将 Header 进行反编码获取到加密的算法,在通过存放在服务器上的密匙对 Header.Payload 这个字符串进行加密,比对JWT 中的 Signature 和实际加密出来的结果是否一致,如果一致那么说明该 JWT 是合法有效的,认证成功,否则认证失败。
在这里插入图片描述

2.4 SSM整合JWT

  1. 导入依赖:java-jwt
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>

依赖josn

  1. 前后端分离的JWT工具类
public class JwtUtil {
    /**
     * 加密密钥
     */
    private static final String SECRET = "LXYgsagag";
    /**
     * 发行人
     */
    private static final String ISSURE="lxy";
    /**
     * 存放用户id的key
     */
    private static final String USERID = "userId";
    /**
     * 存放到jwt中 用户自定义数据的key(比如可以存放 登陆成功的整个用户对象/权限数据)
     */
    private static final String DATA = "data";
    /**
     * 生存时间
     */
    private static final Long EXPIRE_TIME = 60*1000L;
    /**
     * 生成token
     * @param data : 存放的用户数据
     * @param userId : 存放的用户id
     * @param <T> : 数据类型
     * @return
     */
    public static<T> String sign(T data,Integer userId){
        try {
            // 指定加密算法
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            // 计算过期时间
            Date expire = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            // 将用户对象转换成json字符串
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonData = objectMapper.writeValueAsString(data);
            // 生成token
            return JWT.create()
                    .withClaim(USERID, userId)
                    .withClaim(DATA, jsonData)
                    .withExpiresAt(expire)
                    .withIssuer(ISSURE)
                    .sign(algorithm);

        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 验证token的正确性
     * @param token : jwt token
     * @param userId : 存放的用户id
     * @return
     */
    public static Boolean verify(String token , Integer userId){
        try {
            // 指定加密算法
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            // 验证器
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(USERID, userId)
                    .withIssuer(ISSURE)
                    .build();
            // 验证
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 获取保存的用户id
     * @param token
     * @return
     */
    public static Integer getUserId(String token){
        try {
            // 解码token
            DecodedJWT decode = JWT.decode(token);
            return decode.getClaim(USERID).asInt();
        } catch (JWTDecodeException e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 获取用户保存的信息
     * @param token : jwt token
     * @param tClass : 存放数据的class对象
     * @param <T> : 类型
     * @return
     */
    public static <T> T getData(String token,Class<T> tClass){
        try {
            // 解码token
            DecodedJWT decode = JWT.decode(token);
            // 存放的用户数据的json字符串
            String jsonData = decode.getClaim(DATA).asString();
            // 利用jackson将json转换成对象
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(jsonData, tClass);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}
  1. 异常处理
    JwtException.java
public class JwtException extends Exception {
	private Integer code;
	private String msg;
	// 构造器,getter/setter方法
}

MyExceptionHandler.java

@ExceptionHandler(JwtException.class)
public JsonResult jwtExceptionHandler(JwtException e) {
	return new JsonResult(e.getCode(),e.getMsg());
}
  1. 创建拦截器
    AccessInterceptor
public class AccessInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 先从请求头里面去获取jwt token
        String token = request.getHeader("Authorization");
        // 验证是否为空
        if (StringUtils.isEmpty(token)) {
            throw new JwtException(6001,"token 为空!");
        }
        // 获取保存的用户信息
        User user = JwtUtil.getData(token, User.class);
        System.out.println(user);
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

JwtInterceptor.java

public class JwtInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 先从请求头里面去获取jwt token
        String token = request.getHeader("Authorization");
        // 验证是否为空
        if (StringUtils.isEmpty(token)) {
            throw new JwtException(6001,"token 为空!");
        }
        // 获取用户id
        Integer userId = JwtUtil.getUserId(token);
        if(userId == null){
            throw new JwtException(6002,"token 不正确!请重新登陆!");
        }
        // 验证token
        if (!JwtUtil.verify(token,userId)) {
            throw new JwtException(6002,"token 不正确!请重新登陆!");
        }
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}
  1. 控制层JwtController模拟登陆成功
@RestController
public class JwtController {
    @Autowired
    private UserMapper userMapper;
    /**
     * 登陆的方法
     * @param userName
     * @param pwd
     * @return
     */
    @PostMapping("/jwt/login")
    public JsonResult login(String userName, String pwd){
        // 模拟登陆成功
        // 直接生成token
        User dbUser = userMapper.findByName(userName);
        String token = JwtUtil.sign(dbUser, 20);

        return new JsonResult(200,"success",token);
    }
    @PostMapping("/jwt/list")
    public JsonResult getList(){
        return new JsonResult(200,"success");
    }
}
  1. 在postman测试
    在这里插入图片描述
    在这里插入图片描述
发布了79 篇原创文章 · 获赞 7 · 访问量 1833

猜你喜欢

转载自blog.csdn.net/weixin_45044097/article/details/103200652
今日推荐