文章目录
- 一、后端代码
- 1.响应工具类
- 2.jwt工具类
- 3.登录用户实体类
- 4.登录接口
- 5.测试接口
- 6.过滤器
- 7.启动类
- 二、前端代码
- 1.登录页
- index 页面
- 三、效果展示
一、后端代码
1.响应工具类
package com.etime.util;
import com.etime.vo.ResponseModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Date 2024/6/10 10:00
* @Author liukang
**/
public class ResponseUtil {
public static void write(ResponseModel rm, HttpServletResponse response) throws IOException {
// 构造响应头
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding("utf-8");
// 解决跨域问题 设置跨域头
response.setHeader("Access-Control-Allow-Origin","*");
// 输出流
PrintWriter out = response.getWriter();
// 输出
out.write(new ObjectMapper().writeValueAsString(rm));
// 关闭流
out.close();
}
}
2.jwt工具类
package com.etime.util;
import io.jsonwebtoken.*;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
/**
* @Date 2024/6/10 10:04
* @Author liukang
**/
public class JwtUtil {
private static String secret = "secret";
/**
* 创建jwt
* @author liukang
* @date 10:36 2024/6/10
* @param expire
* @param map
* @return java.lang.String
**/
public static String generateToken(long expire, Map map){
// 床jwt构造器
JwtBuilder jwtBuilder = Jwts.builder();
// 生成jwt字符串
String jwt = jwtBuilder
//头部
.setHeaderParam("typ","JWT")
.setHeaderParam("alg","HS256")
// 载荷
.setClaims(map) // 设置多个自定义数据 位置只能放在前面,如果放在后面,那前面的载荷会失效
.setId(UUID.randomUUID().toString())// 唯一标识
.setIssuer("liukang")// 签发人
.setIssuedAt(new Date())// 签发时间
.setSubject("jwtDemo")// 主题
.setExpiration(new Date(System.currentTimeMillis()+expire))//过期时间
// 签名
.signWith(SignatureAlgorithm.HS256,secret)
.compact();
return jwt;
}
/**
* 创建jwt
* @author liukang
* @date 10:36 2024/6/10
* @param expire
* @return java.lang.String
**/
public static String generateToken(long expire){
// 床jwt构造器
JwtBuilder jwtBuilder = Jwts.builder();
// 生成jwt字符串
String jwt = jwtBuilder
//头部
.setHeaderParam("typ","JWT")
.setHeaderParam("alg","HS256")
// 载荷
.setId(UUID.randomUUID().toString())// 唯一标识
.setIssuer("liukang")// 签发人
.setIssuedAt(new Date())// 签发时间
.setSubject("jwtDemo")// 主题
.setExpiration(new Date(System.currentTimeMillis()+expire))//过期时间
// 签名
.signWith(SignatureAlgorithm.HS256,secret)
.compact();
return jwt;
}
/**
* 解析jwt
* @author liukang
* @date 10:36 2024/6/10
* @param jwt
* @return io.jsonwebtoken.Claims
**/
public static Claims parseToken(String jwt){
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(jwt);
Claims playload = claimsJws.getBody();
return playload;
}
}
3.登录用户实体类
package com.etime.entity;
import lombok.Data;
/**
* @Date 2024/6/10 10:39
* @Author liukang
**/
@Data
public class User {
private String username;
private String password;
}
4.登录接口
package com.etime.controller;
import com.etime.entity.User;
import com.etime.util.JwtUtil;
import com.etime.vo.ResponseModel;
import org.springframework.web.bind.annotation.*;
/**
* @Date 2024/6/10 10:38
* @Author liukang
**/
@RestController
@CrossOrigin
public class LoginController {
@PostMapping("/login")
public ResponseModel login(@RequestBody User user){
Integer code = 200;
String msg = "success";
String token = null;
if(user.getUsername().equals("admin")&&user.getPassword().equals("123")){
// 生成jwt
token = JwtUtil.generateToken(1000*10);// 设置有效期为10s
}else {
code = 500;
msg = "failure";
}
return new ResponseModel(code,msg,token);
}
}
5.测试接口
package com.etime.controller;
import com.etime.vo.ResponseModel;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Date 2024/6/10 12:51
* @Author liukang
**/
@CrossOrigin
@RestController
public class TestController {
@PostMapping("/test")
public ResponseModel test() {
return new ResponseModel(200,"success","测试请求接口成功!");
}
}
6.过滤器
package com.etime.filter;
import com.etime.util.JwtUtil;
import com.etime.util.ResponseUtil;
import com.etime.vo.ResponseModel;
import com.sun.deploy.net.HttpResponse;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
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;
/**
* @Description jwt过滤器
* @Date 2024/6/10 9:46
* @Author liukang
**/
@WebFilter(urlPatterns = "/*") // 过滤所有路径
public class JwtFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 得到两个对象
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//直接放行
if(HttpMethod.OPTIONS.toString().equals(request.getMethod())){
filterChain.doFilter(request,response);
return;
}
String requestURI = request.getRequestURI(); // 不含主机和端口号
if(requestURI.contains("/login")){
filterChain.doFilter(request,response);
return;
}
// 得到请求头的信息(accessToken)
String token = request.getHeader("accessToken");
if(!StringUtils.hasText(token)){
//响应前端错误的消息提示
ResponseModel responseModel = new ResponseModel(500,"failure","令牌缺失!");
ResponseUtil.write(responseModel,response);
return;
}
// 解析Token信息
try {
JwtUtil.parseToken(token);
}catch (Exception e){
//响应前端错误的消息提示
ResponseModel responseModel = new ResponseModel(401,"failure","令牌过期!");
ResponseUtil.write(responseModel,response);
return;
}
filterChain.doFilter(request,response);
}
}
7.启动类
package com.etime;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**
* @Author liukang
* @Date 2022/7/4 11:32
*/
@SpringBootApplication
@ServletComponentScan(basePackages = "com.etime.filter")// 这个包下激活WebFilter这个注解
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
二、前端代码
1.登录页
<template>
<div class="hello">
<form>
用户名:<input v-model="username"/>
<br>
密码<input v-model="password" />
<br>
<button @click="login">登录</button>
</form>
</div>
</template>
<script>
export default {
data () {
return {
username:'',
password:'',
}
},
methods:{
login(){
this.axios.post('http://localhost:8088/login',{
username:this.username,
password:this.password,
}).then(response => {
console.log(response.data);
if(response.data.code==200){
sessionStorage.setItem("accessToken",response.data.token)
this.$router.push({ path: 'index'});
}
}).catch(error => {
console.error(error);
});
}
},
}
</script>
<style scoped>
</style>
index 页面
<template>
<div>
<button @click="test">请求受保护的接口</button>
</div>
</template>
<script>
export default {
data () {
return {
}
},
methods:{
test(){
const accessToken = sessionStorage.getItem('accessToken')
let token = null
if(accessToken){
token = accessToken
}
console.log(token)
this.axios.post('http://localhost:8088/test',{},{headers:{accessToken:token}
}).then(response => {
// if(response.data.code==200){
console.log(response.data);
// }
}).catch(error => {
console.error(error);
});
},
},
}
</script>
<style scoped>
</style>
三、效果展示
1.点击登录后,后端给前端办法jwt令牌,前端将其存入sessionStorage中
2.点击【请求后端受保护的接口】按钮
3.继续多次点击【请求后端受保护的接口】按钮
可以看见,请求几次成功后,便显示令牌过期,这是因为,为了测试方便,我们颁发令牌时有效期设置的10秒
4.在请求接口中不传递Token
重新登录并点击【请求后端受保护的接口】按钮