原理描述:
1、第一次登录的时候,生成JWT令牌,并JWT令牌存放在localStorage。
localStorage.setItem('token', token);
2、每次通过axios发送请求的时候,都将这个令牌获取,并放于header中发送。
也就是JWT令牌只在登录的时候,有服务器发过来客户端,并保存在客户端。后面客户通过浏览器进行的每次请求,都需要带上这个保存有jwt令牌的header
(1)从客户端获取token:
token: localStorage.getItem("token") || ""
(2)axios发送的时候,携带token
axios.get(url, { headers: { 'token': this.token // 注意:这里的'token'应该与后端期望的请求头名称一致 } })
3、服务端获取token,并进行判断。
String token = request.getHeader("token");
详细的代码如下:
1、login.html登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>传参数(实体)</title>
<!-- 引入组件库 -->
<script src="js/jquery.min.js"></script>
<script src="js/vue.js"></script>
<script src="js/element.js"></script>
<script src="js/axios-0.18.0.js"></script>
<link rel="stylesheet" href="js/element.css">
</head>
<body>
<div id="app">
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
<script>
new Vue({
el:"#app",
data:{
form: {
name: '',
password: ''
},
tableData: []
},
methods:{
onSubmit() {
var url = `/loginJwt`
axios.post(url, {
name: this.form.name,
password: this.form.password
})
.then(response => {
this.tableData = response.data;
const token = response.data.data;
localStorage.setItem('token', token);
if(this.tableData.data!=null) {
location.href = 'poemList.html'
}
else {
location.href = 'error.html'
}
})
.catch(error=>{
console.error(error);
alert('登录失败,请检查您的用户名和密码');
})
}
}
})
</script>
</body>
</html>
2、poemList.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>显示所有(删除用按钮和链接均实现)</title>
<script src="./js/vue.js"></script>
<script src="./js/axios-0.18.0.js"></script>
</head>
<body>
<h1 align="center">诗人信息列表listAll</h1>
<div id="app" align="center">
<a href="peot_insert.html">新增</a>
<table border="1">
<tr>
<th>id</th>
<th>author</th>
<th>gender</th>
<th>dynasty</th>
<th>title</th>
<th>style</th>
<th>操作</th>
</tr>
<tr v-for="peot in poemList">
<td>{{peot.id}}</td>
<td>{{peot.author}}</td>
<td>{{peot.gender}}</td>
<td>{{peot.dynasty}}</td>
<td>{{peot.title}}</td>
<td>{{peot.style}}</td>
<td>
<!--<button type="button" @click="deleteId(peot.id)">删除</button>-->
<button type="button" @click="deleteId_restful(peot.id)">删除</button>
<a :href="'peot_delete2.html?id='+peot.id">删除</a>
<a :href="'peot_edit.html?id='+peot.id">修改</a>
</td>
</tr>
</table>
</div>
</body>
<script>
new Vue({
el: "#app",
data: {
poemList: [],
token: localStorage.getItem("token") || ""
},
methods: {
findAll() {
var url = `/poem_index1`
axios.get(url, {
headers: {
'token': this.token
}
})
.then(response => {
this.poemList = response.data.data;
})
.catch(error => {
console.log(error);
});
}
},
created() {
this.findAll(); // 组件创建时发送请求
}
});
</script>
</html>
3、controller
package com.example.controller;
import com.example.pojo.Peot;
import com.example.pojo.Result;
import com.example.pojo.Users;
import com.example.service.PeotService;
import com.example.service.Users2Service;
import com.example.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
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.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//在springboot项目中,使用jwt令牌技术进行登录验证。
@RestController
@Slf4j
public class LoginJwtController {
@Autowired
private Users2Service users2Service;
@Autowired
private PeotService peotService;
@PostMapping("/loginJwt")
public Result login(@RequestBody Users users) {
//调用业务层:登录功能
Users loginUser = users2Service.login(users);
//判断:登录用户是否存在
if(loginUser !=null ){
//自定义信息
Map<String , Object> claims = new HashMap<>();
claims.put("id", 123);
claims.put("password",loginUser.getPassword());
claims.put("name",loginUser.getName());
//使用JWT工具类,生成身份令牌
String token = JwtUtils.generateJwt(claims);
System.out.println(token);
Map<String, String> response = new HashMap<>();
response.put("token", token);
return Result.success(token);
}
return Result.error("用户名或密码错误");
}
@GetMapping("/poem_index1")
public Result index1() {
List<Peot> peotList =peotService.findAll();
return Result.success(peotList);
}
}
4、过滤器LoginCheck2Filter
package com.example.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.pojo.Result;
import com.example.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 检查用户是否已经完成登录
*/
@WebFilter(filterName = "loginCheck2Filter",urlPatterns = "/*")
@Slf4j
public class LoginCheck2Filter implements Filter{
//路径匹配器,支持通配符
public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1、获取本次请求的URI
String requestURI = request.getRequestURI();// /backend/index.html
log.info("拦截到请求:{}",requestURI);
//定义不需要处理的请求路径
String[] urls = new String[]{
"/loginJwt",
"/logout",
"/login/**"
};
//2、判断本次请求是否需要处理
boolean check = check(urls, requestURI);
//3、如果不需要处理,则直接放行
if(check){
log.info("本次请求{}不需要处理",requestURI);
filterChain.doFilter(request,response);
return;
}
//3.获取请求头中的令牌(token)
String token = request.getHeader("token");
log.info("从请求头中获取的令牌:{}",token);
if(!StringUtils.hasLength(token)){
log.info("Token不存在");
Result responseResult = Result.error("Token不存在");
//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
String json = JSONObject.toJSONString(responseResult);
response.setContentType("application/json;charset=utf8");
//响应
response.getWriter().write(json);
return;
}
//5.解析token,如果解析失败,返回错误结果(未登录)
try {
JwtUtils.parseJWT(token);
}catch (Exception e){
log.info("令牌解析失败!");
Result responseResult = Result.error("令牌解析失败!");
//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)
String json = JSONObject.toJSONString(responseResult);
response.setContentType("application/json;charset=utf8");
//响应
response.getWriter().write(json);
return;
}
//6.放行
filterChain.doFilter(request, response);
}
/**
* 路径匹配,检查本次请求是否需要放行
* @param urls
* @param requestURI
* @return
*/
public boolean check(String[] urls,String requestURI){
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if(match){
return true;
}
}
return false;
}
}
5、启动类
一定要加上@ServletComponentScan