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 安全验证相关推荐

  1. 基于Vue3.0+Springboot在线购物商城网站设计

    开发技术环境: Idea + Vscode + Mysql + Springboot + vue3.0 基于vue的购物商城网站分为前台功能和后台管理功能,前台功能主要包括基础功能模块.订单管理模块. ...

  2. vue3.0+vant3仿快手/抖音短视频|Vue3+Vite2聊天/直播实例

    vue3.0-douyin 基于vue3.x开发仿抖音app界面小视频+直播聊天实例. 基于Vue3框架技术搭建一款仿抖音APP界面小视频+直播实战案例.运用到了vite2+vue3.0.5+vuex ...

  3. SpringBoot集成JWT实现Token登录验证

    目录 1.1 JWT是什么? 1.2 JWT主要使用场景 1.3 JWT请求流程 1.4 JWT结构 二,SpringBoot集成JWT具体实现过程 2.1添加相关依赖 2.2自定义跳出拦截器的注解 ...

  4. 【应用】SpringBoot -- JWT 实现 token 验证

    JWT JWT 基本介绍 JWT 的优缺点 JWT 消息构成 SpringBoot 集成 JWT 的简单使用 引入 JWT 依赖 配置自定义注解进行访问控制 配置 JWT 拦截器 注册连接器并配置全局 ...

  5. Springboot token令牌验证解决方案 在SpringBoot实现基于Token的用户身份验证

    Springboot token令牌验证解决方案 在SpringBoot实现基于Token的用户身份验证 参考文章: (1)Springboot token令牌验证解决方案 在SpringBoot实现 ...

  6. springboot+vue3物资管理系统实战

    springboot+vue3物资管理系统实战 1.项目适合对象 2.项目涉及技术 3.项目收获 4.效果展示 5.关键代码 1.项目适合对象 有Vue2.Vue3组合api基础知识,TypeScri ...

  7. SpringBoot+vue3对接支付宝支付详细教程

    SpringBoot+vue3对接支付宝支付详细教程 本人也是第一次做这个,是一个刚刚学习自学支付的萌新,目的是在于学习,只是为了记录自己的学习过程,怕以后会忘记,因为我没有企业账号,所以用的是自己的 ...

  8. springboot+vue3健身房管理系统实战

    springboot+vue3健身房管理系统实战 1.项目适合对象 需要有springboot.Vue2.Vue3组合api基础知识,TypeScript基础知识的小伙伴: 没有vue2/vue3.s ...

  9. SpringBoot+Shiro+Vue实现身份验证

    一.需求 1.Vue登录加密填写用户名.密码,点击登录之后提交给后端: 2.后端接收密码,通过shiro实现身份验证: 3.将登录结果返回给前端. 二.流程分析 1.前端将用户名.密码发给后端: 2. ...

最新文章

  1. MaxCompute动态更新表中某个(多个)字段的数据
  2. angular元素属性绑定_AngularJS语法基础及数据绑定——详解各种数据绑定指令、属性应用...
  3. 【收藏】Win10自带的邮件客户端配置腾讯企业邮箱账号详解
  4. 快准牌电脑发软件_电脑如何下载软件
  5. 【剑指Offer】20包含min函数的栈
  6. [转载]Netvault:操作Informix APM将A机备份的数据恢复到B机
  7. Java007-面向对象(多态)
  8. Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件
  9. Google云也想为中国企业服务,正与腾讯浪潮谈合作
  10. ngx_pagespeed 的魔力
  11. php 四级联动插件,JavaScript_jQuery实现的多选框多级联动插件,jQuery 实现的多选框联动插件 - phpStudy...
  12. html css 书签,CSS实现书签图案的效果
  13. 《电力电子技术》王兆安 第二章
  14. directx修复工具win7_[Win] DirectX修复工具 v3.8 增强版
  15. 教育行业 服务器虚拟化,教育行业桌面虚拟化方案
  16. 三维坐标转经纬度_地形图坐标转换小程序使用方法
  17. 套接字基础与UDP通信
  18. 2022-2028年全球与中国插座行业市场深度调研及投资预测分析
  19. 最佳回归模型选择指标——马洛斯CP值
  20. python 对比两张图片是否相同

热门文章

  1. iPhone 9最新概念图曝光,或在官网直接上架!
  2. 交互式多模型 IMM的原理及代码实现(matlab)
  3. JRebel 坡接方法(和网上大部分不一样)
  4. 考研人的快乐瞬间,今天你快乐了吗?
  5. 搭建个人博客(三):Hexo-theme-pure个人博客中博文上传以及分类和标签的设定
  6. Open3D 点云颜色渲染
  7. 江西多措并举推进移动物联网产业发展,增长势头强劲
  8. 【邮件邮箱】点击链接调起微信跳转到公众号、添加好友如何实现?
  9. 集成学习——Boosting之Ada-boost
  10. java使用batik转换svg文件