JWT 认证和Vue配置跨域

622 阅读3分钟

JWT 认证流程

  1. 客户端使用用户名和密码请求登陆。
  2. 服务端收到请求,去验证用户名和密码
  3. 验证成功后,服务端会签发一个Token,再把这个Token发送给客户端。
  4. 客户端收到Token以后可以把它存储在Cookie本地。
  5. 客户端每次向服务端请求资源时需要携带Cookie中该Token。
  6. 服务端收到请求后,验证客户端携带的Token,如果验证成功则返回数据。

优缺点,组成部分

JWT令牌的优点

  1. JWT基于ison,非常方便解析。
  2. 可以在令牌中自定义丰富的内容,易扩展。
  3. 通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高
  4. 资源服务使用]WT可不依赖认证服务即完成授权。

JWT令牌的缺点: JWT令牌较长,占存储空间比较大。

一个JWT实际上就一个字符串,它由三部分组成,头部、负载与签名

  • 头部:描述关于该IWT的最基本信息,例如其类型以及签名所用的算法(如HMAC SHA256 或 RSA)
  • 负载:是存放信息的地方,例如用户的信息。
  • 签证:签证信息,由三部分组成: Header (Base64编码后) Payload (Base64编码后) Secret (盐,必须保密),由点组成的加密字符串

代码实践

依赖

<!-- JWT -->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.2.0</version>
</dependency>

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>
  • 加密,解密,设置过期时间,设置自定义键值对
@Test
void contextLoads() {
    // 加密
    JwtBuilder jwtBuilder = Jwts.builder().setId("1001") // 设置负载内容
            .setSubject("小明") // 这是主体
            .setIssuedAt(new Date()) //设置签发时间
            .signWith(SignatureAlgorithm.HS256, "QFJAVA");// 前算法,后是盐

    String token = jwtBuilder.compact();
    System.out.println(token);

    // 解密
    // Claims:封装的信息
    Claims body = Jwts.parser().setSigningKey("QFJAVA").parseClaimsJws(token).getBody();
    // 获取自定义的键值对
    Object role = body.get("role");
    System.out.println(role);
    System.out.println(body);

    // 设置过期时间
    long exp = System.currentTimeMillis() + 1000 * 60;
    JwtBuilder builder = Jwts.builder().setId("1001")
            .setSubject("小米")
            .setIssuedAt(new Date())
            .signWith(SignatureAlgorithm.HS256, "QFJAVA")
            // 设置过期时间
            .setExpiration(new Date(exp))
            .claim("role", "admin"); // 就是键值对,可以设置自己想要的数据,可以拿到Claims对象,get方法获取自己的数据
    System.out.println(builder.compact());
}

准备内容

再来说下前端,先配置跨域

module.exports = {
  devServer: {
    host: '0.0.0.0', // 可以忽略不写
    port: 8080, // 它是用来修改你打开后的端口号的
    open: true, // 值为 true的话,项目启动时自动打开到浏览器里边, false不会打开
    proxy: {
      '/api': {
        target: 'http://localhost:82', // 跨域请求的公共地址
        ws: false, // 也可以忽略不写,不写不会影响跨域
        changeOrigin: true, // 是否开启跨域,值为 true 就是开启, false 不开启
        pathRewrite: {
          '^/api': ''// 注册全局路径, 但是在你请求的时候前面需要加上 /api
        }
      },
      '/bvcsp': {
        target: 'https://*****',
        changeOrigin: true,
        // 忽略https证书错误
        secure: false,
        rewrite: (p) => p,
        // 添加请求头,可以在浏览器看到
        bypass: function (req, res, options) {
            const proxyUrl = new URL(req.url, options.target).href
            res.setHeader( 'x-req-proxyUrl', proxyUrl )
        }
       },
    }
  }
}

配置axios,因为配置了跨域,这个时候可以直接写api了

import axios from 'axios'

const request = axios.create({
  baseURL: '/api' // 因为配置跨域了
})

// 下面这是拦截器,拦截请求,自动加token令牌
request.interceptors.request.use(
  config => {
    config.headers.token = `${localStorage.getItem('token')}`
    return config
  }
)

export default request

说下如何请求前端登录接口POST请求
    登录接口就是login,传入username和password就可以了

export const Login = function (data) {
  return request({
    method: 'post',
    url: 'login',
    data: qs.stringify(data)
  })
}