SpringBoot学习day2-前后端的交互搭建以及跨域问题、拦截过滤器问题的解决
- 搭建前端项目,实现前后端交互
- 跨域问题处理
- 生成token
- 前端保存用户token,账号
- 在后端搭建管理员token验证的拦截器
- 测试拦截器
搭建前端项目,实现前后端交互
1.复制之前宿舍管理系统的前端项目 命名为newsweb
跨域问题处理
2.前端发送异步请求,出现跨域问题
在后端创建跨域处理过滤器
如下图
代码如下
package org.example.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Collections;/*
* @Configuration注解表明这是一个配置类,可以包含@Bean注解的方法,这些方法将会在Spring容器中注册为Bean。
* */
@Configuration
public class CorsConfig {@Beanpublic CorsFilter corsFilter() {CorsConfiguration corsConfiguration = new CorsConfiguration();//1,允许任何来源corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));//2,允许任何请求头corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);//3,允许任何方法corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);//4,允许凭证corsConfiguration.setAllowCredentials(true);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", corsConfiguration);return new CorsFilter(source);}
}
3.在后端登录成功后,
生成token
导入jwt jar包
<!-- jwt--><!-- https://mvnrepository.com/artifact/com.auth0/java-jwt --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency>
导入JWTUtil
package com.ffyc.ssm.util;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ffyc.ssm.model.Admin;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.HashMap;
import java.util.Map;/*** JWT工具类*/
@Component
public class JWTUtil {/*** 根据用户id,账号生成token* @param* @return*/public static String getToken(Admin admin) {String token = "";try {//过期时间 为1970.1.1 0:0:0 至 过期时间 当前的毫秒值 + 有效时间Date expireDate = new Date(new Date().getTime() + 10000*1000);//秘钥及加密算法Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");//设置头部信息Map<String,Object> header = new HashMap<>();header.put("typ","JWT");header.put("alg","HS256");//携带id,账号信息,生成签名token = JWT.create().withHeader(header).withClaim("id", admin.getAccount()).withExpiresAt(expireDate).sign(algorithm);}catch (Exception e){e.printStackTrace();return null;}return token;}/*** 验证token是否有效* @param token* @return*/public static boolean verify(String token){try {//验签Algorithm algorithm = Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE");JWTVerifier verifier = JWT.require(algorithm).build();DecodedJWT jwt = verifier.verify(token);return true;} catch (Exception e) {//当传过来的token如果有问题,抛出异常return false;}}/*** 获得token 中playload部分数据,按需使用* @param token* @return*/public static DecodedJWT getTokenInfo(String token){return JWT.require(Algorithm.HMAC256("ZCEQIUBFKSJBFJH2020BQWE")).build().verify(token);}}
前端对应的代码router
//路由导航守卫,每当前端发生一次路由跳转时,会自动触发beforeEach().
rout.beforeEach((to,from,next)=>{if(to.path=='/login'){//如果访问登录组件,不需要做任何判断,直接放行return next();//放行到目标组件}else{var token = sessionStorage.getItem("adminToken");if(token==null){ //用户信息为空,说明用户没有登录return next("/login");}else{//说明用户已经登录next();}}
}
main.js
import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = false/* 导入路由 */
import router from './router/index.js'
Vue.use(router);/* 导入 elementUI*/
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);//导入axios组件
import axios from 'axios';
//设置后端默认地址
axios.defaults.baseURL="http://127.0.0.1:8080/";
//将axios对象挂载到vue对象上,并为其指定一个别名
Vue.prototype.$http=axios;//axios 请求拦截, 每当我们使用axios框架向后端发送请求时,都会经过拦截器
axios.interceptors.request.use(config =>{//为请求头对象,添加 Token 验证的 token 字段config.headers.token = sessionStorage.getItem('adminToken');return config;
})// 添加响应拦截器
axios.interceptors.response.use((resp) =>{//正常响应拦截if(resp.data.code==500){ElementUI.Message({message:resp.data.desc,type:"error"});}if(resp.data.code==401){ElementUI.Message({message:resp.data.desc,type:"error"});router.replace("/login");}return resp;
});new Vue({render: h => h(App),router,
}).$mount('#app')
前端保存用户token,账号
登录界面代码(存储token、accout、password)
<!-- 一个.vue文件是一个组件,可以理解为一个页面,但是和页面不同 内容都写在一个template标签中,template标签必须有一个根标签
-->
<template><div class="login_container"><!-- <audio ref="audio" :src="require('./assets/m.mp3')" loop autoplay controls></audio> --><!-- 登录盒子--><div class="login_box"><!-- 头像盒子--><div class="img_box"><img src="./assets/logo.png" /></div><div style="margin-top: 100px; padding-right: 30px;"><el-form ref="form" label-width="80px"><el-form-item label="账号"><el-input v-model="form.account"></el-input></el-form-item><el-form-item label="密码"><el-input v-model="form.password" type="password"></el-input></el-form-item><el-form-item><el-button type="primary" @click="login()">登录</el-button><el-button>取消</el-button></el-form-item></el-form></div></div></div>
</template><script>
/* 导出组件,并为组件定义数据,函数,生命周期函数 */export default{data(){return{form:{account:"admin",password:"111"}}},methods:{login(){if(this.form.account.length==0){this.$message({message: '账号不能为空!',type: 'warning'});return;}if(this.form.password.length==0){this.$message({message: '密码不能为空!',type: 'warning'});return;}//与后端进行交互this.$http.post("loginCtl/login",this.form).then((resp)=>{//根据后端响应回来的结果进行处理resp.data(result对象)if(resp.data.code==200){//前端浏览器中存储用户信息sessionStorage.setItem("adminToken",resp.data.data.adminToken);sessionStorage.setItem("account",resp.data.data.account);sessionStorage.setItem("password",resp.data.data.password);this.$router.push("/main");}else if(resp.data.code==201){this.$message({message: resp.data.desc,type: 'warning'});return;}else{this.$message({message: resp.data.desc,type: 'warning'});return;}});}}}
</script><style>.login_container{height: 100vh;margin: 0px;padding: 0px;background-image: url(assets/bg.jpg);}.login_box{width: 450px;height: 350px;background-color: #fff;border-radius: 10px;position: absolute;left: 50%;top: 50%;transform: translate(-50%,-50%);opacity: 0.95;}.img_box{width: 130px;height: 130px;position: absolute;left: 50%;transform: translate(-50%,-50%);background-color: #fff;border-radius: 50%;padding: 5px;border: 1px solid #eee;}.img_box img{width: 100%;height: 100%;border-radius: 50%;background-color: #eee;}
</style>
在后端搭建管理员token验证的拦截器
jar包
<!--spring中提供的解决跨域问题的过过滤器--><dependency><groupId>com.thetransactioncompany</groupId><artifactId>cors-filter</artifactId><version>2.5</version></dependency>
添加拦截器类
package org.example.interceptor;import org.example.util.JWTUtil;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;//定义拦截器
public class AdminTokenInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("进入到了拦截器");//获得tokenString adminToken = request.getHeader("Token");System.out.println("token:"+adminToken);if(JWTUtil.verify(adminToken)){return true; //拦截器中返回true, 请求就会离开拦截器,继续向后执行,到达处理器}else{response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.write("token验证失败");return false;//拦截器中返回false. 不会继续向后执行. 可以在拦截器中向用户做出响应}}
}
配置拦截器设置WebConfig
package org.example.config;import org.example.interceptor.AdminTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;@Configuration
public class WebConfig implements WebMvcConfigurer{public void addInterceptors(InterceptorRegistry registry) {InterceptorRegistration inter = registry.addInterceptor(new AdminTokenInterceptor());inter.addPathPatterns("/**"); //都得进入拦截器inter.excludePathPatterns("/loginCtl/login");//放行地址inter.addPathPatterns("/user/**"); //用户需要拦截过滤地址}}
测试拦截器
登录进去之后删除Token,点击测试方法
前端测试方法
test(){this.$http.get("loginCtl/test");}
后端测试方法
@RequestMapping(path = "/test")public String test(@RequestBody Admin admin){return "success";}
清空Token
激活test()方法
响应拦截器,返回到了登录界面
对应main.js代码如下
// 添加响应拦截器
axios.interceptors.response.use((resp) =>{//正常响应拦截if(resp.data.code==500){ElementUI.Message({message:resp.data.desc,type:"error"});}if(resp.data.code==401){ElementUI.Message({message:resp.data.desc,type:"error"});// 删除Token、account、passwordsessionStorage.clear();router.replace("/login");}return resp;
});
后端响应