首先做好准备工作,建好前后端项目,配置好。可参考https://segmentfault.com/a/1190000014211773?utm_source=tag-newest
1.发送登录请求,将后台返回的token保存进sessionStorage。
Login.vue
管理员登录:
立即登录
2.main.js中添加请求拦截器,每一个到后端的请求都带上token,未登录就是null,会被后端拦截
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
//引入emlment-ui的提示功能
import {Message} from 'element-ui'
//引入vuex
import Vuex from 'vuex'
import store from './store'
Vue.use(Vuex)
Vue.use(ElementUI);
Vue.prototype.$message=Message
Vue.config.productionTip = false
// 引用axios,并设置基础URL为后端服务api地址
var axios = require('axios')
axios.defaults.baseURL = 'http://localhost:8001/lgtour'
axios.defaults.withCredentials = true //请求发送cookie
// 将API方法绑定到全局
Vue.prototype.$axios = axios
/* eslint-disable no-new */
new Vue({
el: '#app',
router,//路由
store:store,
components: { App },
template: ' ',
emulateJSON:true,
render: h => h(App)
})
// 添加请求拦截器,在请求头中加token
axios.interceptors.request.use(
config => {
if (window.sessionStorage.getItem('token')) {
config.headers.token = window.sessionStorage.getItem('token')
}
return config;
},
error => {
return Promise.reject(error);
});
3.router/index.js中添加导航守卫,让前端每一次路由跳转先判断是否登录。
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Welcome from '@/components/Welcome'
import Login from '@/components/Login'
Vue.use(Router)
const router = new Router({
routes: [
{
path: '/',
name: 'Welcome',
component: Welcome
},
{
path: '/admin/login',
name: 'Login',
component: Login
},
{
path: '/userLogin',
name: 'UserLogin',
component: resolve => require(['@/components/user/UserLogin.vue'],resolve)
}
]
})
// 导航守卫
// 使用 router.beforeEach 注册一个全局前置守卫,判断用户是否登陆
router.beforeEach((to, from, next) => {
if (to.path === '/admin/login') {
next();
} else {
//console.log('before')
let token = window.sessionStorage.getItem('token')
if (token === null || token === '') {
next('/admin/login');
} else {
next();
}
}
});
export default router;
所需依赖pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.0.RELEASE
com.zjjlg
lgtour
0.0.1-SNAPSHOT
lgtour
Demo project for Spring Boot
1.8
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.3
mysql
mysql-connector-java
runtime
com.alibaba
druid
1.1.8
org.projectlombok
lombok
true
1.18.12
com.alibaba
fastjson
1.2.47
log4j
log4j
1.2.17
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-maven-plugin
配置文件,主要配置了druid数据源和log日志,打印数据库操作,方便测试
application.yml
server:
port: 8001
spring:
datasource:
# 数据源基本配置
username: root
password: 962464
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/lgtour?serverTimezone=GMT%2B8&
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
# schema:
# - classpath:sql/department.sql
# - classpath:sql/employee.sql
# initialization-mode: always
# devtools:
# restart:
# enabled: true #是否支持热部署
#mybatis:
# config-location: classpath:mybatis/mybatis-config.xml
# mapper-locations: classpath:mybatis/mapper/*.xml
logging:
level:
com.example.demo.mapper: debug
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
后端返回给前端的数据对象,前后基本使用json传数据,将传递的信息封装起来
Result.java
package com.zjjtour.lgtour.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.io.Serializable;
/**
* 前端返回对象
*/
@Data
public class Result implements Serializable {
private static final long serialVersionUID = 1430633339880116031L;
/**
* 成功与否标志
*/
private boolean success = true;
/**
* 返回状态码,为空则默认200.前端需要拦截一些常见的状态码如403、404、500等
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer status;
/**
* 编码,可用于前端处理多语言,不需要则不用返回编码
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private String code;
/**
* 相关消息
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private String msg;
/**
* 相关数据
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
private Object data;
public Result() {}
public Result(boolean success) {
this.success = success;
}
public Result(boolean success, Integer status) {
this.success = success;
this.status = status;
}
public Result(boolean success, String code, String msg){
this(success);
this.code = code;
this.msg = msg;
}
public Result(boolean success, Integer status, String code, String msg) {
this.success = success;
this.status = status;
this.code = code;
this.msg = msg;
}
public Result(boolean success, String code, String msg, Object data){
this(success);
this.code = code;
this.msg = msg;
this.data = data;
}
}
result生成工具类,快速创建result对象
ResultFactory.java
package com.zjjtour.lgtour.utils;
import com.zjjtour.lgtour.entity.Result;
/**
* Result生成工具类
*/
public class ResultFactory {
protected ResultFactory() {}
public static Result newResult() {
return new Result();
}
public static Result newResult(boolean success) {
return new Result(success);
}
//
// 业务调用成功
// ----------------------------------------------------------------------------------------------------
public static Result success() {
return new Result();
}
public static Result success(String msg) {
return new Result(true, null, msg);
}
public static Result success(String code, String msg) {
return new Result(true, code, msg);
}
public static Result successWithStatus(Integer status) {
return new Result(true, status);
}
public static Result successWithStatus(Integer status, String msg) {
return new Result(true, status, null, msg);
}
public static Result successWithData(Object data) {
return new Result(true, null, null, data);
}
public static Result successWithData(Object data, String msg) {
return new Result(true, null, msg, data);
}
public static Result successWithData(Object data, String code, String msg) {
return new Result(true, code, msg, data);
}
//
// 业务调用失败
// ----------------------------------------------------------------------------------------------------
public static Result failure() {
return new Result(false);
}
public static Result failure(String msg) {
return new Result(false, null, msg);
}
public static Result failure(String code, String msg) {
return new Result(false, code, msg);
}
public static Result failureWithStatus(Integer status) {
return new Result(false, status);
}
public static Result failureWithStatus(Integer status, String msg) {
return new Result(false, status, null, msg);
}
public static Result failureWithData(Object data) {
return new Result(false, null, null, data);
}
public static Result failureWithData(Object data, String msg) {
return new Result(false, null, msg, data);
}
public static Result failureWithData(Object data, String code, String msg) {
return new Result(false, code, msg, data);
}
}
跨域请求过滤器,解决前后分离跨域请求问题,配合@CrossOrigin注解使用
package com.zjjtour.lgtour.component;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/*
* 允许跨域请求
*/
@Configuration
public class PortalCorsFilter extends CorsFilter{
private static Logger logger = LoggerFactory.getLogger(PortalCorsFilter.class);
public PortalCorsFilter() {
super(configurationSource());
}
private static UrlBasedCorsConfigurationSource configurationSource() {
logger.info("init CorsFilter...");
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:8080");
config.addAllowedHeader("*");
config.setMaxAge(36000L);
config.setAllowedMethods(Arrays.asList("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
}
生成token的工具类:(网上找的)
TokenProccessor.java
package com.zjjtour.lgtour.component;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;
import sun.misc.BASE64Encoder;
/**
* 生成Token的工具类
*
*/
public class TokenProccessor {
private TokenProccessor(){};
private static final TokenProccessor instance = new TokenProccessor();
public static TokenProccessor getInstance() {
return instance;
}
/**
* 生成Token
* @return
*/
public String makeToken() {
String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
try {
MessageDigest md = MessageDigest.getInstance("md5");
byte md5[] = md.digest(token.getBytes());
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(md5);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
请求拦截器,拦截所有前端请求,只放行登录请求。在拦截器中判断前端传递的token和后端存入session中的token是否相同,不同就拦截请求,返回错误信息,相同就放行。
MyWebConfig.java
package com.zjjtour.lgtour.component;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.alibaba.fastjson.JSON;
import com.zjjtour.lgtour.utils.ResultFactory;
@Configuration
public class MyWebConfig implements WebMvcConfigurer{
/**
* 登录session key
*/
public final static String SESSION_KEY = "token";
@Bean
public SecurityInterceptor getSecurityInterceptor() {
return new SecurityInterceptor();
}
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor = registry.addInterceptor(getSecurityInterceptor());
// 排除配置
addInterceptor.excludePathPatterns("/error");
addInterceptor.excludePathPatterns("/lgtour/login**");
// 拦截配置
addInterceptor.addPathPatterns("/lgtour/**");
}
//拦截器 内容
private class SecurityInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession();
//登录验证
System.out.println("前端token"+request.getHeader("token"));
String header = request.getHeader("token");
String attribute = (String)session.getAttribute("stoken");
System.out.println("sessionToken"+attribute);
if(header == null ||attribute == null ) {
returnJson(response, JSON.toJSONString(ResultFactory.failureWithStatus(401,"你还未登录或登录已过期,请先登录")));
return false;
}else if(!attribute.equals(header.split(" ")[1])) {
returnJson(response, JSON.toJSONString(ResultFactory.failureWithStatus(401,"你还未登录或登录已过期,请先登录")));
return false;
}else {
return true;
}
}
//返回json数据
private void returnJson(HttpServletResponse response, String json) throws Exception{
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=utf-8");
try {
writer = response.getWriter();
writer.print(json);
} catch (IOException e) {
} finally {
if (writer != null)
writer.close();
}
}
}
}
登录controller
LgAdminController.java
package com.zjjtour.lgtour.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.zjjtour.lgtour.component.TokenProccessor;
import com.zjjtour.lgtour.entity.LgAdmin;
import com.zjjtour.lgtour.entity.Result;
import com.zjjtour.lgtour.service.LgAdminService;
@RestController
@ResponseBody
@CrossOrigin
@RequestMapping("/lgtour")
public class LgAdminController {
@Autowired
LgAdminService lgAdminService;
@RequestMapping("/login")
public Result login(@RequestBody LgAdmin admin,HttpSession session) {
Result result = lgAdminService.login(admin);
System.out.println(result);
if(result.getStatus() == 200) {
//创建token
String token = TokenProccessor.getInstance().makeToken();
session.setAttribute("stoken", token);
result.setData(token);
return result;
}else {
return result;
}
}
@RequestMapping("/test")
public void test() {
System.out.println("通过拦截了");
}
}
service
package com.zjjtour.lgtour.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zjjtour.lgtour.entity.LgAdmin;
import com.zjjtour.lgtour.entity.Result;
import com.zjjtour.lgtour.mapper.LgAdminMapper;
import com.zjjtour.lgtour.utils.ResultFactory;
@Service
public class LgAdminService {
@Autowired
LgAdminMapper lgAdminMapper;
public Result login(LgAdmin admin) {
LgAdmin get = lgAdminMapper.getByName(admin.getName());
if(get == null) {
return ResultFactory.failure("该用户不存在");
}else if(!get.getPassword().equals(admin.getPassword())){
return ResultFactory.failure("密码错误");
}else {
return ResultFactory.successWithStatus(200,"登录成功");
}
}
}
mapper
package com.zjjtour.lgtour.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import com.zjjtour.lgtour.entity.LgAdmin;
@Mapper
public interface LgAdminMapper {
@Select("select * from admin where name=#{name}")
public LgAdmin getByName(String name);
}