springboot+vue3.0+token 安全验证
springboot+vue+token安全验证
- 目录
- 一、说明
- 二、后台(springboot)
- 1、添加依赖包
- 2、添加token工具类
- 3、创建拦截器
- 4、入口拦截
- 5、配置跨域
- 6、登录接口
- 三、前端(vue)
- 1、src目录下创建store文件夹
- 2、添加路由守卫
- 3、添加拦截器
- 4、登录测试
目录
一、说明
在前后端完全分离的情况下,Vue项目中实现token验证大致思路如下(懒得打字,这一部分引用了该博主的内容 Vue项目中实现用户登录及token验证):
1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码
2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token
3、前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面
4、前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面
5、每次调后端接口,都要在请求头中加token
6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401
7、如果前端拿到状态码为401,就清除token信息并跳转到登录页面
二、后台(springboot)
1、添加依赖包
在springboot项目中添加jwt依赖包,这个主要作用是token的加密与解密方法。
<!--jwt 依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
2、添加token工具类
添加token工具类,TokenUtil
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.lin.springMVC.domain.User;import java.util.Date;public class TokenUtil {private static final long EXPIRE_TIME= 10*60*60*1000;private static final String TOKEN_SECRET="txdy"; //密钥盐/*** 签名生成* @param user* @return*/public static String sign(User user){String token = null;try {Date expiresAt = new Date(System.currentTimeMillis() + EXPIRE_TIME);token = JWT.create().withIssuer("auth0").withClaim("userAccount", user.getUserAccount()).withExpiresAt(expiresAt)// 使用了HMAC256加密算法。.sign(Algorithm.HMAC256(TOKEN_SECRET));} catch (Exception e){e.printStackTrace();}return token;}/*** 签名验证* @param token* @return*/public static boolean verify(String token){try {JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();DecodedJWT jwt = verifier.verify(token);System.out.println("认证通过:");System.out.println("userAccount: " + jwt.getClaim("userAccount").asString());System.out.println("过期时间: " + jwt.getExpiresAt());return true;} catch (Exception e){return false;}}
}
3、创建拦截器
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;@Component
public class TokenInterceptor implements HandlerInterceptor {private static final String token = "token#";@AutowiredRedisHandler redisHandler;@Value("${api.api_prefix}")public String api_prefix;/*** 在请求处理之前进行调用,在进入Controller方法之前先进入此方法* 返回true才会继续向下执行,返回false取消当前请求* 登录拦截,权限资源控制工作*/@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler) throws Exception {String userAccount = null;String redirectUrl = "login";if ((httpServletRequest.getParameter("language") != null && !httpServletRequest.getParameter("language").equals("en"))) {redirectUrl += "_en";}Cookie[] cookies = httpServletRequest.getCookies();//从cookie中取值String token1 = httpServletRequest.getHeader("Access-Token");// 从 http 请求头中取出 tokenif(token1 != null){boolean result = TokenUtil.verify(token1);if(result){System.out.println("通过拦截器");return true;}}try{JSONObject json = new JSONObject();json.put("msg","token verify fail");json.put("status","401");httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType("application/json; charset=utf-8");PrintWriter out = null;out = httpServletResponse.getWriter();out.append(json.toString());return false;}catch (Exception e){e.printStackTrace();JSONObject json = new JSONObject();json.put("msg","error");json.put("status","500");httpServletResponse.setCharacterEncoding("UTF-8");httpServletResponse.setContentType("application/json; charset=utf-8");PrintWriter out = null;out = httpServletResponse.getWriter();out.append(json.toString());return false;}}
4、入口拦截
配置入口拦截,ShiroConfiguration类
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;import java.util.LinkedHashMap;
import java.util.Map;import javax.servlet.Filter;/*** shiro配置类*/
@Configuration
public class ShiroConfiguration {/*** Shiro的Web过滤器Factory 命名:shiroFilter*/@Bean(name = "shiroFilter")//相当于<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {//for defining the master Shiro FilterShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();//Shiro的核心安全接口Sets the application {@code SecurityManager} instance to be used by the constructed Shiro Filter.//This is a required property - failure to set it will throw an initialization exception.shiroFilterFactoryBean.setSecurityManager(securityManager);//<property name="securityManager" ref="securityManager"/>Map<String, Filter> filterMap = new LinkedHashMap<>();//Most implementations subclass one of the//{@link AccessControlFilter}, {@link AuthenticationFilter}, {@link AuthorizationFilter} classes to simplify things,//and each of these 3 classes has configurable properties that are application-specific.filterMap.put("authc", new AjaxPermissionsAuthorizationFilter());//添加过滤器shiroFilterFactoryBean.setFilters(filterMap);Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();//相当于<property name="filterChainDefinitions">filterChainDefinitionMap.put("/", "anon");
// filterChainDefinitionMap.put("/debug/**", "anon");filterChainDefinitionMap.put("/static/**", "anon");filterChainDefinitionMap.put("/login", "anon");filterChainDefinitionMap.put("/register", "anon");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}}
5、配置跨域
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;@Configuration
public class CorsConfig {@Beanpublic CorsFilter corsFilter() {final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();final CorsConfiguration corsConfiguration = new CorsConfiguration();/*是否允许请求带有验证信息*/corsConfiguration.setAllowCredentials(true);/*允许访问的客户端域名*/corsConfiguration.addAllowedOrigin("*");/*允许服务端访问的客户端请求头*/corsConfiguration.addAllowedHeader("*");/*允许访问的方法名,GET POST等*/corsConfiguration.addAllowedMethod("*");urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);return new CorsFilter(urlBasedCorsConfigurationSource);}
}
6、登录接口
@PostMapping("/login")@ResponseBodypublic ModelMap userLogin(@RequestBody User userform, HttpServletRequest request, HttpServletResponse response, @RequestHeader("language") String language) {String status;String url = redirectUrl;String token1="";int code;ModelMap result = new ModelMap();Subject currentUser = SecurityUtils.getSubject();try {currentUser.login(token);User user = userService.getUserInfo(userform.getUserAccount(), ShiroUtils.generatePwdEncrypt(userform.getUserPassword(), salt));if (user != null) {try {token1 = TokenUtil.sign(userform);status = "success";code = 200;} catch (JedisConnectionException | RedisConnectionFailureException e) {//用户登录记录userLog(user, request.getRemoteUser(), "login_error:" + e.toString());status = "fail";code = 400;}} else {User userTemp = new User();userTemp.setUserId("null");userTemp.setUserAccount("null");userLog(userTemp, request.getRemoteUser(), "login_error:user is not exist!");status = "fail";code = 401;}} catch (AuthenticationException e) {//用户登录记录User userTemp = new User();userTemp.setUserId("null");userTemp.setUserAccount("null");userLog(userTemp, request.getRemoteUser(), "login_error:user is not exist!");status = "fail";code = 401;}result.put("status", status);result.put("code", code);result.put("token",token1);result.put("url", "null");return result;}
三、前端(vue)
1、src目录下创建store文件夹
在store文件夹下新建 index.js:
[SET_TOKEN]: (state, token: string) => {state.token = token;ls.set(STORAGE_TOKEN_KEY, token);},
2、添加路由守卫
import router from '@/router';
import store from '@/store';
import localStorage from '@/utils/local-storage';
import { allowList, loginRoutePath } from '../define-meta';
import { STORAGE_TOKEN_KEY } from '@/store/mutation-type';
// eslint-disable-next-line
import { GENERATE_ROUTES, GENERATE_ROUTES_DYNAMIC, GET_INFO } from '@/store/modules/user/actions';router.beforeEach(async to => {const userToken = localStorage.get(STORAGE_TOKEN_KEY);// token checkif (!userToken) {// 白名单路由列表检查if (allowList.includes(to.name as string)) {return true;}if (to.fullPath !== loginRoutePath) {// 未登录,进入到登录页return {path: loginRoutePath,replace: true,};}return to;}// check login user.role is nullif (store.getters['user/allowRouters'] && store.getters['user/allowRouters'].length > 0) {return true;} else {const info = await store.dispatch(`user/${GET_INFO}`);// 使用当前用户的 权限信息 生成 对应权限的路由表const allowRouters = await store.dispatch(`user/${GENERATE_ROUTES}`, info);if (allowRouters) {return { ...to, replace: true };}return false;}
});router.afterEach(() => {});
3、添加拦截器
// 请求拦截器
const requestHandler = (config: AxiosRequestConfig,
): AxiosRequestConfig | Promise<AxiosRequestConfig> => {const savedToken = localStorage.get(STORAGE_TOKEN_KEY);// 如果 token 存在// 让每个请求携带自定义 token, 请根据实际情况修改if (savedToken) {config.headers[REQUEST_TOKEN_KEY] = savedToken;}config.headers[language] = 'cn';return config;
};
4、登录测试
[LOGIN]({ commit }, info: LoginParams) {return new Promise((resolve, reject) => {// call ajaxpostAccountLogin(info).then(res => {commit(SET_TOKEN, res.token);resolve(res);}).catch(error => {reject(error);});});},
代码很多,写的比较杂,记录下,怕自己忘记了,之前项目用的cookie,在此基础上修改了下。也多谢下面的大神提供的帮助。
链接: VUE SPRINGBOOT实现TOKEN登录以及访问验证.
链接: Vue项目中实现用户登录及token验证.
springboot+vue3.0+token 安全验证相关推荐
- 基于Vue3.0+Springboot在线购物商城网站设计
开发技术环境: Idea + Vscode + Mysql + Springboot + vue3.0 基于vue的购物商城网站分为前台功能和后台管理功能,前台功能主要包括基础功能模块.订单管理模块. ...
- vue3.0+vant3仿快手/抖音短视频|Vue3+Vite2聊天/直播实例
vue3.0-douyin 基于vue3.x开发仿抖音app界面小视频+直播聊天实例. 基于Vue3框架技术搭建一款仿抖音APP界面小视频+直播实战案例.运用到了vite2+vue3.0.5+vuex ...
- SpringBoot集成JWT实现Token登录验证
目录 1.1 JWT是什么? 1.2 JWT主要使用场景 1.3 JWT请求流程 1.4 JWT结构 二,SpringBoot集成JWT具体实现过程 2.1添加相关依赖 2.2自定义跳出拦截器的注解 ...
- 【应用】SpringBoot -- JWT 实现 token 验证
JWT JWT 基本介绍 JWT 的优缺点 JWT 消息构成 SpringBoot 集成 JWT 的简单使用 引入 JWT 依赖 配置自定义注解进行访问控制 配置 JWT 拦截器 注册连接器并配置全局 ...
- Springboot token令牌验证解决方案 在SpringBoot实现基于Token的用户身份验证
Springboot token令牌验证解决方案 在SpringBoot实现基于Token的用户身份验证 参考文章: (1)Springboot token令牌验证解决方案 在SpringBoot实现 ...
- springboot+vue3物资管理系统实战
springboot+vue3物资管理系统实战 1.项目适合对象 2.项目涉及技术 3.项目收获 4.效果展示 5.关键代码 1.项目适合对象 有Vue2.Vue3组合api基础知识,TypeScri ...
- SpringBoot+vue3对接支付宝支付详细教程
SpringBoot+vue3对接支付宝支付详细教程 本人也是第一次做这个,是一个刚刚学习自学支付的萌新,目的是在于学习,只是为了记录自己的学习过程,怕以后会忘记,因为我没有企业账号,所以用的是自己的 ...
- springboot+vue3健身房管理系统实战
springboot+vue3健身房管理系统实战 1.项目适合对象 需要有springboot.Vue2.Vue3组合api基础知识,TypeScript基础知识的小伙伴: 没有vue2/vue3.s ...
- SpringBoot+Shiro+Vue实现身份验证
一.需求 1.Vue登录加密填写用户名.密码,点击登录之后提交给后端: 2.后端接收密码,通过shiro实现身份验证: 3.将登录结果返回给前端. 二.流程分析 1.前端将用户名.密码发给后端: 2. ...
最新文章
- MaxCompute动态更新表中某个(多个)字段的数据
- angular元素属性绑定_AngularJS语法基础及数据绑定——详解各种数据绑定指令、属性应用...
- 【收藏】Win10自带的邮件客户端配置腾讯企业邮箱账号详解
- 快准牌电脑发软件_电脑如何下载软件
- 【剑指Offer】20包含min函数的栈
- [转载]Netvault:操作Informix APM将A机备份的数据恢复到B机
- Java007-面向对象(多态)
- Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件
- Google云也想为中国企业服务,正与腾讯浪潮谈合作
- ngx_pagespeed 的魔力
- php 四级联动插件,JavaScript_jQuery实现的多选框多级联动插件,jQuery 实现的多选框联动插件 - phpStudy...
- html css 书签,CSS实现书签图案的效果
- 《电力电子技术》王兆安 第二章
- directx修复工具win7_[Win] DirectX修复工具 v3.8 增强版
- 教育行业 服务器虚拟化,教育行业桌面虚拟化方案
- 三维坐标转经纬度_地形图坐标转换小程序使用方法
- 套接字基础与UDP通信
- 2022-2028年全球与中国插座行业市场深度调研及投资预测分析
- 最佳回归模型选择指标——马洛斯CP值
- python 对比两张图片是否相同