前言
前面一篇文章就就介绍了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的前后端算是,结束了,其实还有很多的东西没有写完全,后面会继续补充的。
如果喜欢并解决了你的问题请点赞+评论支持一下