JWT实现前后端交互(SpringBoot+Vue)--代码实现

前言

前面一篇文章就就介绍了JWT的一些简单介绍:https://blog.csdn.net/weixin_45969142/article/details/109892662

1.引入依赖:

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

2.引入工具类

package com.fourgirls.xiaoxiang.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @author jwt
 * @since 2020/04/23
 */
 //组件的注入
@Component
public class JwtUtilstwo {

    //设置过期时间 1天
    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    //设置密钥--随便设置
    public static final String APP_SECRET = "wswxpq";

    public static String getJwtToken(String username) {

        String JwtToken = Jwts.builder()
                //头部
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")

                //这个随便设置
                .setSubject("guli-user")
                //设置过期时间,你当前的时间+过期时间,超过就过期了
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))

                //设置token的主体部分,存储用户信息--可以加多行
//                .claim("id", id)
                .claim("username", username)

                //生成秘钥的方法--由签名+加密算法
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     *
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
        if (StringUtils.isEmpty(jwtToken)) {
            return false;
        }
        try {
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断token是否存在与有效
     *
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if (StringUtils.isEmpty(jwtToken)) {
                return false;
            }
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取用户username
     *
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        System.out.println("jwtToken:"+jwtToken);
        if (StringUtils.isEmpty(jwtToken)) {
            return "";
        }
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String) claims.get("username");
    }
}

3.编写登录代码

(1).Mapper层

@Mapper
public interface UserMapper {
  /**
     * 查询User表中的用户的登录数据
     *
     * @return 查询的数据
     */
    public int findLoginUser(LoginVo loginVo);
    }

(2).Mapper.xml —就略写一下,大家知道就行了

<!--    查询User表中的用户的登录数据-->
<select id="findLoginUser" resultType="java.lang.Integer">
    select * from user where userName=#{userName} and password=#{password};
</select>

(3).Service层

public interface UserMapper {
  /**
     * 查询User表中的用户的登录数据
     *
     * @return 查询的数据
     */
    public int findLoginUser(LoginVo loginVo);
    }

(4).ServiceImpl层

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    UserMapper userMapper;
    
      /**
     *
     * @param loginVo
     * @return
     */
    @Override
    public int findLoginUser(LoginVo loginVo) {
        return userMapper.findLoginUser(loginVo);
    }
    }

(5).Controller层

@RestController
//跨域
@CrossOrigin
public class UserController {

    @Autowired
    UserService userService;

    @Autowired
    JwtUtils jwtUtils;
    
    /**
     * 查询User表中的用户的登录数据
     * @return 查询的数据
     */
    @ApiOperation(value = "用户登录生成Token")
    @RequestMapping("findloginuser")
    public R findLoginUser(@RequestBody LoginVo loginVo){

        int result = userService.findLoginUser(loginVo);
        System.out.println("result:"+result);
        if (result > 0){
            String token = JwtUtils.getJwtToken(loginVo.getUserName());
            System.out.println("token:"+token);
            return R.ok().data("token",token);
        }
        return  R.error();
    }
}

(6).R的异常类

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

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

//统一返回结果的类
@Data
public class R {

    @ApiModelProperty(value = "是否成功")
    private Boolean success;

    @ApiModelProperty(value = "返回码")
    private Integer code;

    @ApiModelProperty(value = "返回消息")
    private String message;

    @ApiModelProperty(value = "返回数据")
    private Map<String, Object> data = new HashMap<String, Object>();

    //把构造方法私有
    private R() {}

    //成功静态方法
    public static R ok() {
        R r = new R();
        r.setSuccess(true);
        r.setCode(ResultCode.SUCCESS);
        r.setMessage("成功");
        return r;
    }

    //失败静态方法
    public static R error() {
        R r = new R();
        r.setSuccess(false);
        r.setCode(ResultCode.ERROR);
        r.setMessage("失败");
        return r;
    }

    public R success(Boolean success){
        this.setSuccess(success);
        return this;
    }

    public R message(String message){
        this.setMessage(message);
        return this;
    }

    public R code(Integer code){
        this.setCode(code);
        return this;
    }

    public R data(String key, Object value){
        this.data.put(key, value);
        return this;
    }

    public R data(Map<String, Object> map){
        this.setData(map);
        return this;
    }
}


(7).Result类

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

/**
 * 返回数据封装类
 * @author wsw
 * @time 2020-12-10
 */
public class Result extends HashMap<String, Object> {

    private static final long serialVersionUID = 1L;

    public Result() {
        put("code", 1);
        put("data", 1);
        put("msg", "success");
    }

    public static Result error() {
        return error(500, "未知异常,请联系管理员");
    }

    public static Result error(String msg) {
        return error(500, msg);
    }

    public static Result error(int code, String msg) {
        Result r = new Result();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }

    public static Result ok(String msg) {
        Result r = new Result();
        r.put("msg", msg);
        return r;
    }

    public static Result ok(Map<String, Object> map) {
        Result r = new Result();
        r.putAll(map);
        return r;
    }

    public static Result ok() {
        return new Result();
    }

    @Override
    public Result put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}

4.生成Token

在这里插入图片描述

5.前端接受Token并且存储到cookie中

(1).安装cookie

 npm install --save js-cookie

(2).引入js-cookie

import cookie from 'js-cookie';

(3).编写访问的APi-request.js,下面会有引入该js,注意路径位置就行了。

封装了axios的Htttp请求,可以让我们通过http访问后台的时候,对http的一些信息进行操作,就比如下面的可以在htttp中头部head加入token

import axios from 'axios';
import cookie from 'js-cookie';

export function request(config) {
    //创建axios实例
    const service = axios.create({
        baseURL: 'http://localhost:8088/xiaoxiang',
        timeout: 30000,
    })
    //HTTP request 拦截器 user(用户) request(请求) service(服务)的时候 interceptors(拦截)
    service.interceptors.request.use(
        config => {
            //如果存在
            if (cookie.get('username')!=null) {
                //把获取出来的cookie值放到head里面
                config.headers['token'] = cookie.get('username');
                console.log('cookie.get(\'username\'):'+cookie.get('username'))
            }
            return config
        },
        err => {
            return Promise.reject(err);
        })
    return service(config);
}
export default request;

(4).编写登录界面—这里你们可以换自己的登录,因为有些静态资源啥的你们可能拿不到

<template>
    <div id="bigBox">
        <div class="background">
            <img :src="imgSrc" width="100%" height="100%" alt/>
        </div>
        <h1>欢迎使用潇湘大药房</h1>
        <div class="inputBox">
            <div class="inputText">
                <!-- span没有固定的格式表现。当对它应用样式时,它会产生视觉上的变化。 -->
                <span class="fa fa-user-o" aria-hidden="true"></span>
                <input type="text" placeholder="请输入用户名" v-model="username"/>
            </div>
            <div class="inputText">
                <span class="fa fa-key" aria-hidden="true"></span>
                <input type="password" placeholder="请输入密码" v-model="password"/>
            </div>
            <div style="position: absolute;margin-top: 10px;margin-left: 75px;transform: scale(0.8);">
                <div>
                    <el-select v-model="value" @on-change="chickvalue" placeholder="请选择身份">
                        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
                        </el-option>
                    </el-select>
                </div>


            </div>

            <div>
                <a class="register" v-on:click="Register"
                   style="position: absolute;margin-top: 60px;margin-left: -100px;">没有账号就先注册吧</a>
            </div>
            <input type="button" v-on:click="Login" class="inputButton" value="登录"/>
            <input type="button" class="inputButton" value="忘记密码"/>
        </div>
        <router-view></router-view>
    </div>
</template>

<script>
    import cookie from 'js-cookie'
    import {request} from '../../utils/request'

    export default {
        name: "Login",
        data() {
            return {
                options: [{
                    value: 'admin',
                    label: 'admin'
                }, {
                    value: '普通用户',
                    label: '普通用户'
                }],
                value: '',
                searchValue: '',
                imgSrc: require("../../assets/Loginbackground.jpg"),
                username: '',
                password: '',
                identity: ''
            }
        },
        methods: {
            onSelectedDrug(id) {
                let obj = {};
                obj = this.expressList.find((item) => { //这里的userList就是上面遍历的数据源
                    return item.abbreviation === id; //筛选出匹配数据
                });
                console.log(obj.express); //获取的 name
                console.log(id); //获取的 id
            },

            //登录的方法
            Login() {
                console.log("this.username:"+this.username)
                var that = this;
                request({
                    url: '/findloginuser',
                    method: 'post',
                    data: {
                        userName: this.username,
                        password: this.password
                        //indentity: this.value
                    }
                }).then(function(res){
                    console.log("res:",res.data.data.token);
                    if(res != null) {
                        //放入cookie中
                        cookie.set('username', res.data.data.token, {domain: 'localhost'})
                        if (that.value === "admin") {
                            that.$router.push("/MedicineManage/" + that.username + "/药品管理")
                        } else if (that.value === "普通用户") {
                            that.$router.push("/views/ShouYe/" + that.username + "/首页")
                        }
                    }
                }).catch(function(err) { //请求失败
                    console.log(err)
                })
            },

            // Login() {
            // 	//axios 获取网络
            // 	var that = this
            // 	this.$axios.post("http://localhost:8088/xiaoxiang/findloginuser", {
            // 		userName: this.username,
            // 		password: this.password,
            // 		indentity: this.value
            // 	}).then(function(res) { //请求成功
            // 		//回调方法里的this,只是调用方法体里面的参数,所以需要在外面将this定义好 JQuery
            // 		console.log(res.data.data)
            // 		if (res.data.code === 1) {
            // 			// JSON.stringify将要序列化成 一个JSON 字符串的值
            // 			sessionStorage.setItem("user", JSON.stringify({
            // 				username: that.username,
            // 			}))
            //
            // 			// //放入cookie中
            // 			// cookie.set('username',res.data.data.token,{domain: 'localhost'})
            //
            // 			if (that.value === "admin") {
            // 				that.$router.push("/MedicineManage/" + that.username + "/药品管理")
            // 			} else if (that.value === "普通用户") {
            // 				that.$router.push("/views/ShouYe/" + that.username + "/首页")
            // 			}
            //
            //
            // 		} else if (res.data.code === 500) {
            // 			console.log("登录失败")
            // 			alert("用户名或者密码错误,请重新输入")
            // 			// window.location.href = 'fail.html'
            // 		}
            // 	}).catch(function(err) { //请求失败
            // 		console.log(err)
            //
            //
            // 	})
            // },
            Register() {
                console.log("点击了注册")
                this.$router.push("/Logins/Register")
            }
        }
    }
</script>

<style src="../../config/font-awesome-4.7.0/css/font-awesome.css"></style>
<style scoped>
    /*@import "src/config/font-awesome-4.7.0/css/font-awesome.css";*/
    #bigBox .background {
        width: 100%;
        height: 100%;
        /**宽高100%是为了图片铺满屏幕 */
        z-index: -1;
        position: fixed;
        top: 0px;
        /*这里是设置与顶部的距离*/
        left: 0px;
        /*这里是设置与左边的距离*/
        bottom: 0px;
        right: 0px;
    }


    #bigBox {
        margin: 0 auto;
        margin-top: 200px;
        /* 	上内边距和下内边距是 20px
            右内边距和左内边距是 50px */
        padding: 20px 50px;
        background-color: #00000090;
        width: 400px;
        height: 300px;
        /* border-radius这个属性算是非常常用的属性之一了,
        通过设置元素的border-radius值,可以轻松给元素设置圆角边框,
        甚至实现绘制圆、半圆、四分之一的圆等各种圆角图形。 */

        /* 常用来给button加圆角边框,或者画一个圆形按钮,仅需设置一个数值,
        即可给元素的四个边角设置统一的圆角弧度,根据px的大小来改变 */
        border-radius: 10px;
        text-align: center;
    }

    #bigBox h1 {
        color: white;
    }

    #bigBox .inputBox {
        margin-top: 0px;
    }

    #bigBox .inputBox .inputText {
        margin-top: 20px;
    }

    #bigBox .inputBox .inputText input {
        /* 边框 */
        border: 0;
        padding: 10px 10px;
        /* 设置下边框大小为1px,实线,颜色为白色. */
        border-bottom: 1px solid white;
        background-color: #00000000;
        color: white;
    }

    #bigBox .inputBox .inputText span {
        color: white;
    }

    #bigBox .inputBox .register {
        width: 150px;
        height: 20px;
        margin-top: 20px;
        /* 用了颜色轻柔 */
        background-image: linear-gradient(120deg, #a6c0fe 0%, #f68084 100%);
    }

    #bigBox .inputBox .inputButton {
        border: 0;
        width: 150px;
        height: 20px;
        color: white;
        margin-top: 100px;
        border-radius: 20px;
        /* 用了颜色轻柔 */
        background-image: linear-gradient(120deg, #a6c0fe 0%, #f68084 100%);
    }
</style>

登录中的重点:前面那些div啥的肯定不管,管的都是登录里面的方法:

引入要用的js

在这里插入图片描述

登录方法详解

在这里插入图片描述

输入登录信息后,就打印了

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

如何看cookie

在这里插入图片描述

(5).将登录存储到http的请求头中去了

就是前面封装的axios请求
在这里插入图片描述

6.后台验证token是否有效

在刚才的controller中,我加入了一个新的方法

@RestController
//跨域
@CrossOrigin
public class UserController {

    @Autowired
    UserService userService;

    @Autowired
    JwtUtils jwtUtils;
    
    /**
     * 查询User表中的用户的登录数据
     * @return 查询的数据
     */
    @ApiOperation(value = "用户登录生成Token")
    @RequestMapping("findloginuser")
    public R findLoginUser(@RequestBody LoginVo loginVo){

        int result = userService.findLoginUser(loginVo);
        System.out.println("result:"+result);
        if (result > 0){
            String token = JwtUtils.getJwtToken(loginVo.getUserName());
            System.out.println("token:"+token);
            return R.ok().data("token",token);
        }
        return  R.error();
    }
    
    /**
     * 根据username查询,user表中的信息
     * @return 查询的数据
     */
    @RequestMapping("findUserNameUser")
    public R findUserNameUser(HttpServletRequest httpServletRequest){
        //HttpServletRequest得到Http请求里面的信息
        System.out.println("httpServletRequest:"+httpServletRequest);
        //HttpServletRequest得到Http请求里面请求头中key值为token的信息
        System.out.println("httpServletRequest:"+httpServletRequest.getHeader("token"));
        
        //HttpServletRequest得到Http请求里面请求头中key值为token的信息 --这里是将token信息进行解密,并且得到用户名的值
        //可以去看看该方法,就懂了,不详细介绍了
        String username = JwtUtils.getMemberIdByJwtToken(httpServletRequest);
        System.out.println("username"+username);

        UserNameVo userNameVo = new UserNameVo();
        userNameVo.setUserName(username);
        return R.ok().data("data", userService.findUserNameUser(userNameVo));
    }
    }

7.验证前端传回来token是否有效

这里就需要引入接口进行测试了我用的是postwoman,其他的测试工具都可
在这里插入图片描述

8.前端如何传输token过去呢?

其实前面就已经将cookie封装到HTTP请求头中了,所以前端只需要进行进行一个http请求就可以了,后台自己去拿那个请求头就可以了

下面我自己将一个search方法,直接点按钮就能将用户名传过去了

searchBook() {
				var that = this
				request({
					url: '/findUserNameUser',
					method: 'post'
				}).then(function(response) {
					console.log("response.data.data.data:"+response.data.data.data)
					that.tableData = response.data.data.data.data
					console.log("response",response)
				})
			}

在这里插入图片描述

9.清除一下cookie方法—要记得清除缓存,不然可能会出错

在这里插入图片描述

10.结束语

JWT的前后端算是,结束了,其实还有很多的东西没有写完全,后面会继续补充的。

如果喜欢并解决了你的问题请点赞+评论支持一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值