session共享问题和其他常见问题及解决方案

news2024/11/25 6:48:09

目录

1.shiro+springboot中session的共享问题

1.1 如何解决session共享问题

2. 解决前端不支持cookie的效果

2.1.如何把sessionId放入请求头

2.2.重写DefaultWebSessionManager的方法

3.设置前端前置路由守卫

4.如何防止恶意重复登录

5.退出

6.获取当前登录用户的信息

7.设定登录设备的个数



1.Springboot整合Shiro中session的共享问题

问题演示:

(1)启动shiro-springboot的集群项目

 

 两个启动

(2)修改nginx的配置

 (3)测试

登录成功后访问某些资源时,出现了未登录的json提示  

1.1 如何解决session共享问题

默认session存储再各自服务的内存中,可以让session统一存储再redis中。

疯狂的蛋糕的依赖。---提供了redis存储session的类。

修改shiro的配置类(ShiroConfig.java)

@Bean
    public DefaultWebSecurityManager securityManager() {
        // 创建默认的 Web 安全管理器
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置安全管理器使用的 Realm
        securityManager.setRealm(myRealm());
        securityManager.setCacheManager(redisCacheManager());
        //设置session管理器
        securityManager.setSessionManager(sessionManager());
        // 返回安全管理器
        return securityManager;
    }
    @Bean
    public SessionManager sessionManager(){  //session管理器
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        //setSessionDAO用于操作session对象,在容器中对象session进行CRUD操作
        sessionManager.setSessionDAO(sessionDao());
        return sessionManager;
    }
    @Bean
    public SessionDAO sessionDao(){
        //该类会对对象session进行CRUD操作
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("192.168.75.129:6379");
        sessionDAO.setRedisManager(redisManager);
        return sessionDAO;
    }

核心:DefaultWebSessionManager获取请求头中的JSESSIONID的值,

          通过RedisSessionDAO从redis中查询该值对应的key,如果存在则认为当前用户登录

2. 解决前端不支持cookie的效果

问题演示:

后台UserController添加:

前端参考Vue脚手架工程

 前端Login.vue修改  

 前端Product.vue修改  

 测试:登录

 登录之后,点击权限-查询,直接报错--跨域

原因:

默认DefaultWebSessionManager它只接受Cookie中存储的JsessionId. 查询发现再redis中不存在对应的key.

如何解决:

客户发送请求时,在请求头中携带sessionId, 然后重写DefaultWebSessionManager中getSessionId()的方法。

思考:1. 如何把sessionId放入请求头。

        2. 重写getSessionId方法如何获取请求头的sessionID。

2.1.如何把sessionId放入请求头

修改登录的接口

修改前端登录方法

修改main.js文件  

//设置axios的请求拦截器
axios.interceptors.request.use(config=>{
  //从localStorage中获取token的值
  var item = localStorage.getItem("token");
  if (item){
    config.headers.token=item;
  }
  return config;
})

 灰色依赖删除

2.2.重写DefaultWebSessionManager的方法

创建MyWebSessionManager .java



import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.util.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

public class MyWebSessionManager extends DefaultWebSessionManager {
    private static final String AUTHORIZATION = "token";
    private static final String REFERENCED_SESSION_ID_SOURCE = "Stateless request";
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        //获取请求头中名称为token的内容
        String id = WebUtils.toHttp(request).getHeader("token");
        if (!StringUtils.isEmpty(id)) { //如果存在该token
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "Stateless request");
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        } else {
            //从cookie中获取sessionId.
            return super.getSessionId(request, response);
        }
    }
}

修改shiro配置类

在LoginFilter过滤器添加:

这里发现跨域请求,会发送两个请求:第一个OPTIONS请求,第二个请求是真实的请求。

OPTIONS请求:先头部队。

所以我们对OPTIONS请求都要放行

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        HttpServletRequest req = (HttpServletRequest) request;

        String method = req.getMethod();
        if("OPTIONS".equals(method)){
            return true;
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }

3.设置前端前置路由守卫

//设置前置路由守护-----登录才能访问里面的资源
router.beforeEach((to,from,next)=>{
  //to:到哪去  from:从哪来  next:下一站
  //获取路由的路径
  var  path = to.path;
  if (path == "/login"){
    return next();
  }
  //判断是否登录过
  var token = sessionStorage.getItem("token");
  if (token){
    return next();
  }
  return next("/login");
})

 把localStorage改为sessionStorage

 

4.如何防止恶意重复登录

添加:

5.退出

编辑退出接口

 @PostMapping("/logout")
    public Result logout(){
        Subject subject = SecurityUtils.getSubject();
        //清空redis
        subject.logout();
        return new Result(200,"退出成功",null);
    }

编辑前端退出按钮

6.获取当前登录用户的信息

编辑查询信息接口

编辑前端退出按钮

点击获取用户名字

7.设定登录设备的个数

演示:一个账号只能登录两个设备

加依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

配置文件

#配置redis
spring.redis.host=192.168.75.129
LoginController
@Controller
//默认*允许所有域都可以跨域访问该接口
/*@CrossOrigin*/
public class LoginController {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @PostMapping("/login")
    @ResponseBody
    public Result login(@RequestBody LoginVo loginVo) {
        // 获取当前主体对象
        Subject subject = SecurityUtils.getSubject();
        // 创建用户名密码令牌
        UsernamePasswordToken token = new UsernamePasswordToken(loginVo.getUsername(), loginVo.getPassword());
        try {
            String key = "shiro:user:" + loginVo.getUsername();
            ValueOperations<String, String> foValue = redisTemplate.opsForValue();
            int count = 0;
            String c = foValue.get(key);
            if (c != null) {
                if (Integer.parseInt(c) >= 1) {
                    return new Result(400, "同时在线设备不能超过2台", subject.getSession().getId());
                } else {
                    count++;
                }
            } else {
                count = 0;
            }
            subject.login(token);
            foValue.set(key, count + "");
            return new Result(200, "登录成功~~~", subject.getSession().getId());
        } catch (Exception e) {
            e.printStackTrace();
            // 登录失败,重定向到登录页面
            return new Result(500, "登录失败", null);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/743319.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jQuery根据数据动态创建表格:列固定,行超出滚动条,绑定td点击事件等

示例如图&#xff0c;代码如下: html: <div class"layui-row" id"avTableulL"><ul></ul></div><div id"avTableulR"><div id"avTableulT"><ul></ul></div><div id"avT…

【华为认证】HCIP-Datacom 2023最新题库

正在备考华为认证的小伙伴应该知道&#xff0c;除了理论知识外&#xff0c;刷题也相当重要&#xff0c;周工这里有一份HCIAHCIP-Datacom带解析的最新题库 点赞留言 即可领取。 1. &#xff08;多选题&#xff09;ISIS的Hello报文主要分为哪几种类型? A.P2P LAN IIH B.…

UnityVR--机械臂场景12-简单流水线应用4

目录 一. 手爪 二. 红外线传感器 三. 工件生成器 四. 总结 上一篇已经实现了机械臂各种动作的控制&#xff0c;本篇实现一下其余的组成部分&#xff0c;比如手爪、传感器和自动放置工件等。 一. 手爪 手爪的模型调整就不多说了&#xff0c;需要设置的是Rigidbody、Collide…

在Visual Studio Code里导出8266固件

1.编辑 .vscode目录下 arduion.json 添加 一个配置项output即输出目录.当然你不设置其它软固件一样会生成,只是就不知道你能不能找到了.我的配置如下 当然这个路径你想写什么 就是什么 . 2. 切换到 arduion的项目文件 xxxx.ino.点击vsc右上的验证 即可在上面设置的目录下找到…

Nginx系列之 一 入门

目录 一、Nginx概述 二、yum安装 三、nginx.conf配置文件详解 3.1 全局块 3.2 events 块 3.3 HTTP 块 四、Nginx 常用命令 五、Nginx代理 4.1 正向代理 4.2 反向代理 六、Nginx的Master-Worker模式 6.1 Master进程的作用是&#xff1f; 6.2 Worker进程的作用是&am…

Layui动态树详解

Layui动态树详解 一、什么是动态树形&#xff1f;二、Layui动态树形基本使用三、动态加载数据4.案列1.实体类2.dao方法3.子实现类4.jsp页面 前言 在前端开发过程中&#xff0c;树形控件是比较常用的控件之一。而Layui框架中&#xff0c;也提供了基于jQuery的树形控件。除了普通…

小程序接口返回errno: 600009 errMsg: “request:fail invalid url “异常问题排查修复记录

小程序封装wxrequest更换域名baseurl后调用接口返回errMsg: "request:fail invalid url "&#xff0c;errno: 600009 控制台输出request的url也是正常的&#xff0c;起初怀疑是没配置域名白名单&#xff0c;但是小程序模拟器勾选了不校验合法域名的&#xff0c;而且…

PWM技术在嵌入式设备运行中的调节应用

PWM&#xff08;脉宽调制&#xff09;是一种通过改变信号的脉冲宽度来控制电压或电流的技术。PWM的等效电压是指将PWM信号转换为相应的直流电压或电流的数值。 在PWM信号中&#xff0c;占空比表示高电平和低电平脉冲宽度的比例。例如&#xff0c;一个占空比为50%的PWM信号意味…

ApiPost - 踩坑指南

1.应用场景 主要用于记录apipost遇到的坑, 以及为遇到的开发者提供参考. 2.学习/操作 1.文档阅读 chatgpt & 其他资料 ApiPost问答-localhost的坑的问题列表 localhost 不能正确解析为本机-ApiPost使用-ApiPost问答 断网了&#xff0c;还能ping通 127.0.0.1 吗&#xff1…

基于STM32的智能花盆系统设计与实现(华为云IOT)

一、设计需求 1.1 设计需求总结 伴随着人们生活水平以及现在科学技术的急速发展,越来越多的人喜欢在家庭栽培一些盆栽植物。可是当代生活节奏过快,导致盆栽大多数都不能得到很好的补充水分和阳光照射,从而导致盆栽的生活周期变短。如何利用现代电子技术设计一种可自动浇水…

Android Java代码与JNI交互 JNI访问Java类方法 (七)

🔥 Android Studio 版本 🔥 🔥 创建包含JNI的类 JNIAccessMethod.java 🔥 package com.cmake.ndk1.jni;import com.cmake.ndk1.model.Animal;public class JNIAccessMethod {static {System.loadLibrary("access-method-lib");}public native void access…

Spring Bean生命周期以及PostProcessor后置处理器

简介 所谓Bean的生命周期&#xff0c;就是一个 Bean 从创建到销毁&#xff0c;所经历的各种方法调用。 一个Bean的生命周期分为四个阶段&#xff1a; 实例化(Instantiation)&#xff1a;Spring容器负责创建Bean的实例&#xff0c;可以通过构造方法或者无参构造方法进行实例化…

电脑应用程序发生异常怎么办?

有时候我们打开电脑上面的某个软件时&#xff0c;会打不开&#xff0c;并且会弹出如下的错误提示“应用程序发生异常 未知的软件异常&#xff08;&#xff58;&#xff58;&#xff58;&#xff09;&#xff0c;位置为&#xff58;&#xff58;”。相信大多数的人在使用电脑的时…

springMVC(三)—— 整合SSM框架

环境 IDEA Mysql 5.7.19 tomcat 8 maven 3.8.4 数据库设计 CREATE DATABASE ssmbuild;USE ssmbuild;DROP TABLE IF EXISTS books;CREATE TABLE books(bookID INT(10) NOT NULL AUTO_INCREMENT COMMENT 书id,bookName VARCHAR(100) NOT NULL COMMENT 书名,bookCounts INT(…

github 最简单的使用步骤(个人学习记录~)

github 使用步骤&#xff1a; (11条消息) github新手用法详解&#xff08;建议收藏&#xff01;&#xff01;&#xff01;&#xff09;_github详解_怪 咖的博客-CSDN博客 1.获取ssh密钥 打开输入&#xff1a;ssh-keygen -t rsa -C “git账号” 输入之后一路Enter&#xff08…

Tomcat之高可用配置

Nginx搭配Tomcat实现负载均衡 传统模型下&#xff0c;一个项目部署在一台tomcat上&#xff0c;这个时候&#xff0c;假如tomcat因为服务器资源不够&#xff0c;突然挂机了&#xff0c;那么整个项目就无法使用。 Nginx就可以避免单台服务如果挂机&#xff0c;依然能保证服务正…

Python实现操作MySQL【增删改查】

闲话少叙,直接上操作! 一、准备工作 1.本地安装MySQL、Python(以3.6为例) 2.MySQL新建数据库【test】,新建表【user】,新建字段【name】【age】 3.建表方式:navicat工具 字段 二、Python操作—插入数据 #!/usr/bin/env # coding=utf-8import pymysql # Python 连…

Matlab+Yalmip求解优化问题(1)-入门学习

博客中所有内容均来源于自己学习过程中积累的经验以及对yalmip官方文档的翻译&#xff1a;YALMIP 1.Yalmip工具箱的下载与安装 1.1下载 Yalmip的作者是Johan Lfberg&#xff0c;是由Matlab平台编程实现的一个免费开源数学优化工具箱&#xff0c;在官网上就可以下载。官方下载…

Spark学习--4、键值对RDD数据分区、累加器、广播变量、SparkCore实战(Top10热门品类)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、键值对RDD数据分区1.1 Hash分区1.2 Ranger分区 二、累加器三、广播变量四、SparkCore实战4.1 数据准备4.2 需求&#xff1a;Top10热门品类4.2.1 需求分析&#…

问题解决:错误: 找不到或无法加载主类 App

问题描述尝试解决 问题描述 昨天刚刚把公司的项目源代码拉下来,结果全是报错,几百条.一看就是环境没配好. 今天刚刚解决配置问题,项目也没有报错了 今天在做项目的时候,我先跑一下看看项目能不能跑起来.结果一跑又报错了 错误:找不到或无法加载主类 xxx.BaasAppApplication原因…