社会你“小峰哥“用Java实现了管理员可以修改任意用户Session的功能 上

简介: 社会你“小峰哥“用Java实现了管理员可以修改任意用户Session的功能 上

1 Session会话简介

session 是另一种记录服务器和客户端会话状态的机制,并且session 是基于 cookie 实现的。服务器要知道当前请求发给自己的是谁,为了做这种区分,服务器就是要给每个客户端分配不同的"身份标识",然后客户端每次向服务器发请求的时候,都带上这个“身份标识”。

Cookie是浏览器实现的一种数据存储技术。一般由服务器生成,发送给浏览器(客户端也可进行cookie设置)进行存储,下一次请求同一网站时会把该cookie发送给服务器。

567aa614584f111e7df6c3d7679ebc3.png

2 简单实例准备

我们做一个简单实例,模拟用户登录,以及获取登录用户信息;

新建一个springboot项目modify-session,最终目录结构如下:

b9ced6de40f94194e1bd677295410cf.png

项目pom.xml,引入一个web依赖即可;

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.java1234</groupId>
    <artifactId>modify-session</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>modify-session</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

启动类ModifySessionApplication:

package com.java1234;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ModifySessionApplication {
    public static void main(String[] args) {
        SpringApplication.run(ModifySessionApplication.class, args);
    }
}

项目配置文件application.yml

server:
  port: 80
  servlet:
    context-path: /

用户实体类User

package com.java1234.entity;
/**
 * 用户信息
 * @author java1234_小锋
 * @site www.java1234.com
 * @company 南通小锋网络科技有限公司
 * @create 2021-08-03 21:14
 */
public class User {
    public Integer id;
    public String userName;
    private String password;
    private String level="common";  // common  普通会员  vip  vip会员
    public User() {
    }
    public User(Integer id, String userName, String password) {
        this.id = id;
        this.userName = userName;
        this.password = password;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getLevel() {
        return level;
    }
    public void setLevel(String level) {
        this.level = level;
    }
}

新建一个UserController,提供两个接口方法,分别是模拟用户登录,和获取用户信息:

package com.java1234.controller;
import com.java1234.entity.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpSession;
/**
 * 用户controller
 * @author java1234_小锋
 * @site www.java1234.com
 * @company 南通小锋网络科技有限公司
 * @create 2021-08-03 21:10
 */
@RestController
@RequestMapping("/user")
public class UserController {
    /**
     * 模拟用户登录
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpSession session){
        User uesr=new User(1,"java1234","123456");
        session.setAttribute("currentUser",uesr);
        System.out.println(session.getId());
        return "success";
    }
    /**
     * 获取当前用户信息
     * @param session
     * @return
     */
    @RequestMapping("/getUserInfo")
    public User getUserInfo(HttpSession session){
        return (User)session.getAttribute("currentUser");
    }
}

我们启动项目;

浏览器地址栏输入:http://localhost/user/login

19f02e3bc13c977e05833c078984d83.png

浏览器地址栏输入:http://localhost/user/getUserInfo 获取用户信息

8fca0595b9d9cb4f28030f0522d12bd.png

后端打印出sessionId

7e74dec5cf05d003e22a4b3b914e2d0.png

我们通过谷歌开发者工具,F12;

3db8d4deb71d5b815b85493b4ae05b8.png

后端同时返回了SessionId,作为Cookie;

浏览器地址栏输入:http://localhost/user/getUserInfo

返回用户信息,同时我们看到,请求的时候带了Cookie里的SessionId,去后端查询指定Session信息;

6dcd42c5f3fa4f4bc36185d31ad32b8.png

3 动态修改用户Session场景分析

当前用户自身是可以通过sesssion.setAttribute方法修改session信息的。

2440598d4da7f3e349599fc3848ad93.png

但是我们在某些情况,业务上要求非自身用户修改Session;

比如管理员后台充值好vip后,数据是修改了,但是登录用户的Session没变化,用户看到的依然是非Vip,需要重新登录后,才能看到vip信息,用户体验就差劲了;如果我们可以动态的去修改任意一个用户的Session信息,那用户无需登录,刷新网页就立即能看到vip信息,那用户体验就上来了。

4 动态修改Session原理介绍

我们终极解决方案如下图:

9325c851539dc66cdcc299c369f0a0c.png

我们可以创建一个Session监听器,来监听用户Session的创建和销毁事件,所以这里,我们可以去维护一个sessionId和Session对象关系的存储介质,一般情况下可以用HashMap,正好是key-value键值对,假如高并发情况,也可以存储到告诉缓存Redis,当然对象的话,注意要序列化;

同时每次用户登录后,我们可以得到userId和sessionId,我们也用一个存储介质维护起来,我们这里为了测试方便,用servletContext全局上下文存储,高并发下,依然要选用Redis存储;

有了以上两个核心的存储介质加上session监听器,我们就可以实现动态修改Session了;

具体步骤如下:

第一步:用户登录,得到sessionId和userId;

第二步:把sessionId和userId存储到servletContext全局上下文,格式 { userId : sessionId } ;

第三步:登录请求触发session监听器的sessonCreated方法;

第四步:sessionCreated方法添加session信息到HashMap,格式 { sessionId : session对象 } ;

第五步:管理员登录,根据userId去servletContext查询sessionId;

第六步:得到sessionId后去hashMap里去查询session对象;

通过以上步骤,得到指定用户的Session对象后,就可以任意操作了;

目录
相关文章
|
19天前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
81 34
|
1月前
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
121 60
|
1月前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
35 2
|
1月前
|
存储 安全 搜索推荐
理解Session和Cookie:Java Web开发中的用户状态管理
理解Session和Cookie:Java Web开发中的用户状态管理
75 4
|
2月前
|
Java 程序员
在Java编程中,关键字不仅是简单的词汇,更是赋予代码强大功能的“魔法咒语”。
【10月更文挑战第13天】在Java编程中,关键字不仅是简单的词汇,更是赋予代码强大功能的“魔法咒语”。本文介绍了Java关键字的基本概念及其重要性,并通过定义类和对象、控制流程、访问修饰符等示例,展示了关键字的实际应用。掌握这些关键字,是成为优秀Java程序员的基础。
35 3
|
2月前
|
Java 数据安全/隐私保护
Java ffmpeg 实现视频加文字/图片水印功能
【10月更文挑战第22天】在 Java 中使用 FFmpeg 实现视频加文字或图片水印功能,需先安装 FFmpeg 并添加依赖(如 JavaCV)。通过构建 FFmpeg 命令行参数,使用 `drawtext` 滤镜添加文字水印,或使用 `overlay` 滤镜添加图片水印。示例代码展示了如何使用 JavaCV 实现文字水印。
179 1
|
2月前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
32 1
|
安全 算法 Java
Java 17 新功能介绍(LTS)
Java 17 新功能介绍(LTS)
703 0
Java 17 新功能介绍(LTS)
|
Java 测试技术 API
Java 18 新功能介绍
Java 18 新功能介绍
327 0
Java 18 新功能介绍
|
JavaScript 前端开发 算法
超详细 Java 15 新功能介绍
超详细 Java 15 新功能介绍
175 0
超详细 Java 15 新功能介绍