SpringBoot集成JWT token实现权限验证

JWT=JSON Web Token

1. JWT的组成

JWT==Header,Payload,Signature==>abc.def.xyz

地址:JSON Web Tokens - jwt.er

1.1 Header

Header:标头。

两个组成部分:令牌的类型(JWT)和所使用的签名算法,经过Base64 Url编码后形成的JWT的第一部分。

{
    "type":"JWT",
    "alg":"HS256"
}

1.2 Payload

Payload---有效负载。存放用户自定义消息

注意点:是以明文的形式进行展示,以Base64进行编码。

{
    “sub":"123",
    "name":"jon",
    "admin":true
}

1.3 Signature

signature--签名。使用标头的算法和私钥对第一部分和第二部分进行加密,通过Base64 Url编码后形成JWT的第三部分。

var encodeString =base64UrlEncode(header)+"."+base64UrlEncode(payload);
var signature=HMACSHA356(encodeString,secret);

2.JWT的基本使用

1.导入pom JWT依

JDK1.8以下的加入JWT依赖即可

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

JDK1.8以上的加上其他

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>

2.创建JWT

    //毫秒
    private long time=1000*60*60*24;
    //签名
    private String signature="admin";

    /*JWT加密*/
    @Test
    public void jwt(){
        //构建JWT对象:Jwts.builder()
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken = jwtBuilder
                //header:头部
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //payload:载荷
                .claim("username", "tom")
                .claim("role", "admin")
                .setSubject("admin-test")
                //有效时间===>一天=当前时间+24小时
                //获得当前的系统时间:System.currentTimeMillis()
                .setExpiration(new Date(System.currentTimeMillis() + time))
                //设置id字段
                .setId(UUID.randomUUID().toString())
                //signature:签名
                //注意点:这个签名算法要与前面的算法一致
                //设置加密算法和签名
                .signWith(SignatureAlgorithm.HS256, signature)
                //将前面3个重要信息拼接起来,使用”."来连接
                .compact();
        System.out.println(jwtToken);
    }

3.验证JWT

    @Test
    /*验证JWT*/
    public void checkJwt(){
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM2MzgzMDMsImp0aSI6ImU5ZjY3ZjBhLWE0NTAtNGYzYy1hYTY3LTU3ZGMwOWRjMDM4ZCJ9.FxA5c91E2bk2KW1rdMo8jlmClXgn7r2mVSaXs19Qzzk";
        //Jwts.parser():解析
        JwtParser jwtParser = Jwts.parser();
        //验证该token是否符合JWT规则
        boolean result = Jwts.parser().isSigned(token);
        System.out.println(result);//true
    }

4.解析JWT

    @Test
    /*解析JWT*/
    public void parseJwt(){
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InRvbSIsInJvbGUiOiJhZG1pbiIsInN1YiI6ImFkbWluLXRlc3QiLCJleHAiOjE2OTM2MzgzMDMsImp0aSI6ImU5ZjY3ZjBhLWE0NTAtNGYzYy1hYTY3LTU3ZGMwOWRjMDM4ZCJ9.FxA5c91E2bk2KW1rdMo8jlmClXgn7r2mVSaXs19Qzzk";
        //获取JWT的解析对象
        JwtParser jwtParser = Jwts.parser();
        //通过signature对token进行签名,解开
        //parseClaimsJws:将JWT转换为key-value的形式,通过key来获取对应的value
        //Jws<Claims>:类似于Map集合
        Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
        //获取Jws对象中的数据:get(key)表示根据key来获取value
        //相当于将header和payload封装为一个claims
        Claims claims = claimsJws.getBody();//存储的是用户保存的数据
        Object username = claims.get("username");
        System.out.println(username);
        Object role = claims.get("role");
        System.out.println(role);
        String id = claims.getId();
        System.out.println(id);
        //签名
        String subject = claims.getSubject();
        System.out.println(subject);
        //有效期
        Date time = claims.getExpiration();
        System.out.println(time);
    }

3.SpringBoot + vue +JWT

 1.导入pom JWT依

JDK1.8以下的加入JWT依赖即可

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

JDK1.8以上的还要加上以下依赖

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-core</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>

2.导入工具类

public class JwtUtil {

    //毫秒
    private static long time=1000*60*60*24;
    //签名
    private static String signature="admin";

    public static String createToken(){
        //构建JWT对象:Jwts.builder()
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken=jwtBuilder
                //header
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //payload
                .claim("username", "admin")
                .claim("role", "admin")
                .setSubject("admin-test")
                //有效时间===>一天=当前时间+24小时
                //获得当前的系统时间:System.currentTimeMillis()
                .setExpiration(new Date(System.currentTimeMillis()+time))
                .setId(UUID.randomUUID().toString())
                //signature
                //注意点:这个签名算法要与前面的算法一致
                .signWith(SignatureAlgorithm.HS256,signature)
                //将前面3个重要信息拼接起来
                .compact();
        return jwtToken;
    }
}

3.在后台解决跨域问题

@Configuration//配置类
public class CoreConfiguration implements WebMvcConfigurer {


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")//所有接口
                .allowCredentials(true)//是否发送Cookie
                .allowedOriginPatterns("*")//支持域
                .allowedMethods("GET","POST","PUT","DELETE")//支持方法
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

4.前台登录界面

5.前端代码

  methods:{
    handleSubmit(){
      this.$refs.ruleForm.validate((valid)=>{
        if(valid){
          let _this=this
          axios.get("http://localhost:8080/login",
              {param:_this.ruleForm}).then(function (response){
            console.log(response.data)
          })
        }
      })
    }
  }

6.进行路由跳转,并且将用户信息存到本地存储中

JSON.stringify-->将JSON转换为字符串

    handleSubmit(){
      this.$refs.ruleForm.validate((valid)=>{
        if(valid){
          let _this=this
          axios.get("http://localhost:8080/login",
              {param:_this.ruleForm})./*带着用户输入的用户名和密码*/
              then(function (response){
                console.log(response.data)
                //如果data不为空,则表示登录成功
                if(response.data!=null){
                  //使用localStorage
                  //将JSON转换为字符串
                  localStorage.setItem('access-admin',JSON.stringify(response.data))
                  //跳转到首页
                  _this.$router.replace({path:"/"})
                  }
                })
          }
      })
    }

7.将用户信息展示到页面中

JSON.parse--->将字符串转换为JSON

<template>
<div>
  欢迎回来:{{admin.username}}
</div>
</template>

  data(){
    return{
      admin:''
    }
  },
  created() {
//获取数据
    this.admin=JSON.parse(window.localStorage.getItem("access-admin"));
  },

8.添加验证用户信息是否存在【在路由中写】

/router/index.js

router.beforeEach((to,from,next)=>{
    if(to.path.startsWith('/login')){
        window.localStorage.removeItem('access-admin')
        next()
    }else {
        let admin=JSON.parse(window.localStorage.getItem('access-admin'))
        if(!admin){
            next({path:'/login'})
        }else {
            //校验token合法性
            axios({
                url:'http://localhost:8080/checkeToken',
                method:'get',
                headers:{
                    token:admin.token
                }
            }).then((response)=>{
                if(!response.data){
                    console.log("校验失败");
                    next({path:'/error'})
                }
            })
        }
    }
})

9.后端验证Token方法

UserController

    /**
     * 验证token方法
     */
    @GetMapping("/checkToken")
    public Boolean checkToken(HttpServletRequest request){
        //因为前端是将数据存储在header,所以我们要是有getHeader
        String token = request.getHeader("token");
        return JwtUtil.checkToken(token);
    }

JwtUtil

    /**
     * 校验token是否正确
     */
    public static boolean checkToken(String token){
        if (token==null){
            return false;
        }
        try {
            //解析
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

4.Springboot+JWT

User

@Data
public class User {
    private String username;
    private String password;
    private String token;
}

UserController:生成JWT令牌

public class UserController {

    private final String USERNAME = "admin";
    private final String PASSWORD = "123123";

    @GetMapping("/login")
    public User login(User user){
        //判断是否正确
        if(USERNAME.equals(user.getUsername()) && PASSWORD.equals(user.getPassword())){
            //添加token;token保存到user对象
            //定义一个工具类,将生成JWT
            user.setToken(JwtUtil.createToken());
            return user;
        }
        return null;
    }
}

JwtUtil:生成JWT令牌

public class JwtUtil {

    //毫秒
    private static long time=1000*60*60*24;
    //签名
    private static String signature="admin";

    public static String createToken(){
        //构建JWT对象:Jwts.builder()
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken=jwtBuilder
                //header
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                //payload
                .claim("username", "admin")
                .claim("role", "admin")
                .setSubject("admin-test")
                //有效时间===>一天=当前时间+24小时
                //获得当前的系统时间:System.currentTimeMillis()
                .setExpiration(new Date(System.currentTimeMillis()+time))
                .setId(UUID.randomUUID().toString())
                //signature
                //注意点:这个签名算法要与前面的算法一致
                .signWith(SignatureAlgorithm.HS256,signature)
                //将前面3个重要信息拼接起来
                .compact();
        return jwtToken;
    }
}

【前端直接传递token】

JwtUtil:验证JWT是否过期

    /**
     * 校验token是否过期
     */
    public static boolean checkToken(String token){
        if (token==null || token==""){
            return false;//false表示令牌过期
        }
        try {
            //拿到JWT对象
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

UserController:验证JWT是否过期

    /**
     * 验证token是否过期:前端传递token
     */
    @GetMapping("/checkToken")
    public Boolean checkToken(String token){
        return JwtUtil.checkToken(token);
    }

【将Token放入请求头中,使用request】

 JwtUtil:验证JWT是否过期

    /**
     * 校验token是否过期
     */
    public static boolean checkToken(String token){
        if (token==null || token==""){
            return false;//false表示令牌过期
        }
        try {
            //拿到JWT对象
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(signature).parseClaimsJws(token);
        }catch (Exception e){
            e.printStackTrace();
        }
        return true;
    }

UserController:验证JWT是否过期

    /**
     * 验证token是否过期:前端将数据封装在请求头中
     * @param request
     * @return
     */
    public boolean checkToken(HttpServletRequest request){
        //getHeader中的key要与前端通过一致
        String token = request.getHeader("token");//key-->token
        return JwtUtil.checkToken(token);
    }

解决跨域问题

参考:SpringBoot跨域请求的问题_m0_63077733的博客-CSDN博客

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 所有接口
                .allowCredentials(true) // 是否发送 Cookie
                .allowedOriginPatterns("*") // 支持域
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}

拦截器实现Token验证

@Configuration
public class TokenInterceptor implements HandlerInterceptor {

    //在请求处理方法被调用之前被调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //前提:token放在请求头中
        String token = request.getHeader("token");
        if (!JwtUtil.checkToken(token)) {
            return false;//验证失败
        }
        return true;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值