JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。

 1.新建springboot应用,添加依赖

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第1张图片

 



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.6.7
         
    
    com.zsp
    jwt_springboot
    0.0.1-SNAPSHOT
    jwt_springboot
    jwt_springboot
    
        1.8
    
    
        
            org.springframework.boot
            spring-boot-starter
        

        
            com.baomidou
            mybatis-plus-boot-starter
            3.2.0
        

        
            mysql
            mysql-connector-java
            runtime
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            org.springframework.boot
            spring-boot-starter-web
        


        
            com.auth0
            java-jwt
            3.4.0
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                
                    
                        
                            org.projectlombok
                            lombok
                        
                    
                
            
        
    


2.编写配置文件,连接数据库,定义端口,定义mapper映射

server.port=8082

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mypractice?serverTimezone=Asia/Shanghai&autoReconnect=true&useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456

mybatis-plus.mapper-locations=classpath:mapper/*.xml
mybatis-plus.type-aliases-package=com.zsp.entity

3.整体目录

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第2张图片

 

 

 controller层,定义两个接口。登录接口和验证测试接口。代码里调用了jwtUtils工具类,

 //生成JWT令牌
 String token = jwtUtils.getToken(payload);

自己定义的,在后面有说明。

package com.zsp.controller;


import com.baomidou.mybatisplus.extension.api.ApiController;
import com.zsp.entity.Users;
import com.zsp.service.UserService;
import com.zsp.utils.jwtUtils;
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.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class UserController extends ApiController {
    @Autowired
    private UserService userService;
    @GetMapping("/user/login")
    public Map login(Users users){
        Map map=new HashMap<>();
        try {
            if (users.getUsername()==null || users.getPassword()==null){
                map.put("state", false);
                map.put("msg", "账户或密码为空");
                return map;
            }
            Users usersDB = userService.login(users);
            Map payload = new HashMap<>();
            payload.put("id", String.valueOf(usersDB.getId()));
            payload.put("name", usersDB.getUsername());
            //生成JWT令牌
            String token = jwtUtils.getToken(payload);
            map.put("state", true);
            map.put("msg", "认证成功");
            map.put("token", token);
        } catch (Exception e){
            map.put("state", false);
            map.put("msg", e.getMessage());
        }
        return map;
    }

    @PostMapping("/user/test")
    public Map test(){
        Map map=new HashMap<>();
        //处理自己的业务逻辑
        map.put("state",true);
        map.put("msg","请求成功");
        return map;
    }
}

Dao层定义登录方法

UserDao层

package com.zsp.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zsp.entity.Users;
import org.apache.ibatis.annotations.Mapper;


@Mapper
public interface UserDao extends BaseMapper {
    //用户登录
    Users login(Users users);
}

 UserDao.XML





    


entity层

package com.zsp.entity;


import com.baomidou.mybatisplus.extension.activerecord.Model;
import java.io.Serializable;

/**
 * (User)表实体类
 *
 * @author makejava
 * @since 2022-05-19 15:20:46
 */
@SuppressWarnings("serial")
public class Users extends Model {
    
    private Integer id;
    
    private String username;
    
    private String password;


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * 获取主键值
     *
     * @return 主键值
     */
    @Override
    protected Serializable pkVal() {
        return this.id;
    }
    }

service层和serviceImpl

package com.zsp.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zsp.entity.Users;

/**
 * (User)表服务接口
 *
 * @author makejava
 * @since 2022-05-19 15:20:46
 */
public interface UserService extends IService {
    //用户登录
    Users login(Users users);
}

package com.zsp.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsp.dao.UserDao;
import com.zsp.entity.Users;
import com.zsp.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * (User)表服务实现类
 *
 * @author makejava
 * @since 2022-05-19 15:20:46
 */
@Service("userService")
@Transactional
public class UserServiceImpl extends ServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public Users login(Users users) {
        Users login = userDao.login(users);
        if (login != null) {
            return login;
        }
        throw new RuntimeException("登录失败");
    }
}

以上就是基本的业务代码。

下面开始做JWT工具类,也就是utils包下的工具类。

package com.zsp.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Calendar;
import java.util.Map;

public class jwtUtils {
//自己定义的签名,可以更改  !Q@W#E$R121121
    private static final String SIGN="!Q@W#E$R121121";
    //JWT生成Token
    public static String getToken(Map map){
        Calendar instance=Calendar.getInstance();
        instance.add(Calendar.DATE,7); //默认7天过期
        JWTCreator.Builder builder = JWT.create();
        map.forEach((k,v)->{
            //payload
            builder.withClaim(k,v);
        });
        String token = builder.withExpiresAt(instance.getTime()) //过期时间
                .sign(Algorithm.HMAC256(SIGN));//signature 签名

        return token;
    }

    //    JWT验证token合法性,并获取信息
    public static DecodedJWT verify(String token){
        //创建验签对象
        DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
        return verify;
    }

    //获取token信息的方法
//    public static DecodedJWT getTokenInfo(String token){
//        //创建验签对象
//        DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIGN)).build().verify(token);
//        return verify;
//    }
}

具体来讲工具类就是:

首先:

jwt 分为三部分:

header  payload  signature

首先定义一个签名,用来做验证。因为服务器通过jwt生成token令牌发给客户端   或者   服务器验证客户端携带的token的请求时,都需要用到这个签名。

原理:客户端请求服务器认证,服务器生成JWT(Token)令牌交给客户端保存,客户端存入header中的Author中。每次请求就携带这个Author

参数传map类型是因为        payload中的 withClaim方法,接收key,value形式

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第3张图片

然后就是传入过期时间和签名。相当于以下这种写法,只不过下面这种的payload是写死的,上面的用map来让用户自定义的。

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第4张图片

 接着就是jwt验证token,也就是你客户端发过来消息,走到我接口这我先验证你这个token是不是我发给你的,有没有被篡改,这个时候签名就是自己定义的。

JWT.require方法进行验签,接收前端传来的token和指定的签名。

jwt验证已经做好了,接下来就是何时进行验证。当前端请求掉后台接口时,通过拦截器的方式看是否携带token。现在做拦截器

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第5张图片

 

先写一个拦截规则。怎么拦截

在前端调用后台controller时进行拦截

package com.zsp.Interceptor;
//怎么拦截

import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zsp.utils.jwtUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Map map=new HashMap<>();
        //获取前端header头携带的token
        String token = request.getHeader("token");
        try {
            jwtUtils.verify(token);//验证令牌
            return true;//放行请求
        } catch (SignatureVerificationException e) {
            e.printStackTrace();
            map.put("msg","拦截器拦截:无效签名");
        }catch (TokenExpiredException e) {
            e.printStackTrace();
            map.put("msg","拦截器拦截:token过期");
        }catch (AlgorithmMismatchException e) {
            e.printStackTrace();
            map.put("msg","拦截器拦截:token算法不一致");
        }catch (Exception e) {
            e.printStackTrace();
            map.put("msg","拦截器拦截:token无效");
        }
        map.put("state",false);//设置状态
        //将map转为json jackson
        String json = new ObjectMapper().writeValueAsString(map);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
        return false;
    }
}

再写一个拦截哪些

package com.zsp.Interceptor;

//拦截哪些
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    //覆盖父类中添加拦截器的方法
    //参数1:InterceptorRegistry 拦截器注册对象
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()) //这里是刚才创建的拦截器
                .addPathPatterns("/user/test")  //拦截哪些  拦截所有
                .excludePathPatterns("/user/login");//排除哪些  排除login
                //添加拦截器
    }
}

最后进行测试。Postman

首先调用login,匹配数据库是否存在,

Users usersDB = userService.login(users);

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第6张图片

 

如果存在,注入payload

payload.put("id", String.valueOf(usersDB.getId()));
payload.put("name", usersDB.getUsername());

调用工具类生成令牌的方法返回前端

 

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第7张图片

此时生成了token。

接着调用后台测试接口。

JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第8张图片

需要在header头里面加入生成的token

 JWT生成token返回前端,前端请求服务器时携带并通过拦截器方式进行token验证。_第9张图片

验证通过。 

 

你可能感兴趣的:(笔记,spring,boot,java)