【SpringBoot3】Spring Security 常用配置总结

注:本文基于Spring Boot 3.2.1 以及 Spring Security 6.2.1

相关文章

【SpringBoot3】Spring Security 核心概念
【SpringBoot3】Spring Security 常用注解
【SpringBoot3】Spring Security 详细使用实例(简单使用、JWT模式)
【SpringBoot3】Spring Security使用mybatis-plus存储用户角色权限,实现动态权限处理

一、Spring Security 常用配置总结

1、记住我 rememberMe

1)配置HttpSecurity,如下代码

// 开启rememberMe,登录表单增加 <input type="checkbox" name="remember-me">
http.rememberMe(Customizer.withDefaults());

2)登录表单页面增加勾选参数,在登录时勾选即可

注意参数名remember-me是默认的,也可以通过配置修改

<input type="checkbox" name="remember-me">

登录成功后,会生成一个cookie(remember-me)

3)配置rememberMe其他参数

  • rememberMeParameter,表单参数名称
  • rememberMeCookieName,记录在浏览器的cookieName
  • tokenValiditySeconds,有效时间,单位秒
http.rememberMe(rm -> rm
        .rememberMeParameter("rememberMe")
        .rememberMeCookieName("rememberMeCookieName")
        .key("rememberMe")
        .tokenValiditySeconds(1800));

2、退出处理

// 退出时,设置session无效
http.logout(logout -> logout.invalidateHttpSession(true));

3、持久化登录令牌

持久化登录令牌是记住我功能的补充,可以将登录的token存储在数据库中。

参考 JdbcTokenRepositoryImpl 可以得知需要创建一张表 persistent_logins

本例使用 mybatis-plus + mysql 存储

1)创建持久化令牌表 persistent_logins

create table persistent_logins (username varchar(64) not null, series varchar(64) primary key,  token varchar(64) not null, last_used timestamp not null)

2)创建实体和Mapper

@Data
@TableName("persistent_logins")
public class UserToken {
    private String username;

    private String series;

    @TableField("token")
    private String tokenValue;
    @TableField("last_used")
    private Date date;
}

@Mapper
public interface UserTokenMapper extends BaseMapper<UserToken> {
}

3)创建自定义持久化类 MyPersistentTokenRepositoryImpl 实现接口 PersistentTokenRepository

@Service
public class MyPersistentTokenRepositoryImpl implements PersistentTokenRepository {
    @Resource
    private UserTokenMapper userTokenMapper;

    @Override
    public void createNewToken(PersistentRememberMeToken token) {
        UserToken userToken = BeanUtil.toBean(token, UserToken.class);
        userTokenMapper.insert(userToken);
    }

    @Override
    public void updateToken(String series, String tokenValue, Date lastUsed) {
        LambdaUpdateWrapper<UserToken> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(UserToken::getSeries, series)
                .set(UserToken::getTokenValue, tokenValue)
                .set(UserToken::getDate, lastUsed);
        userTokenMapper.update(updateWrapper);
    }

    @Override
    public PersistentRememberMeToken getTokenForSeries(String seriesId) {
        UserToken userToken = userTokenMapper.selectOne(new LambdaQueryWrapper<UserToken>().eq(UserToken::getSeries, seriesId));
        PersistentRememberMeToken meToken = BeanUtil.toBean(userToken, PersistentRememberMeToken.class);
        return meToken;
    }

    @Override
    public void removeUserTokens(String username) {
        userTokenMapper.delete(new LambdaQueryWrapper<UserToken>().eq(UserToken::getUsername, username));
    }
}

4)在 HttpSecurity 中配置使用

@Resource
private MyPersistentTokenRepositoryImpl tokenRepository;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    
    // --- 忽略其他代码 --- //
    
    http.rememberMe(rm -> rm
            .rememberMeParameter("rememberMe")
            .rememberMeCookieName("rememberMeCookieName")
            .key("rememberMe")
            // 配置持久化类
            .tokenRepository(tokenRepository)
            .tokenValiditySeconds(1800));
     
     // --- 忽略其他代码 --- //
}

5)登录,勾选记住我
在这里插入图片描述
打开数据库查看,存储正常

在这里插入图片描述

4、并发登录控制,后登录踢掉前面登录

设置每个账户最大的session数量

// 每个账户最大的session数量
http.sessionManagement(sm->sm.maximumSessions(1));

5、主动踢人下线

1)配置 SessionRegistry

/**
 * 通过 SessionRegistry 可以获取到当前登录的所有用户
 * @return
 */
@Bean
public SessionRegistry sessionRegistry(){
    return new SessionRegistryImpl();
}

在 HttpSecurity 中配置

// 每个账户最大的session数量,配置 sessionRegistry
http.sessionManagement(sm->sm.maximumSessions(1).sessionRegistry(sessionRegistry()));

2)在controller中获取在线用户,并展示

@GetMapping("/index")
public String index(Model model) {
    // 获取所有登录过的用户
    List<Object> allPrincipals = sessionRegistry.getAllPrincipals();
    // 移除不存在session的用户
    List<Object> list = allPrincipals.stream().filter(p -> {
        List<SessionInformation> allSessions = sessionRegistry.getAllSessions(p, false);
        return !allSessions.isEmpty();
    }).toList();
    model.addAttribute("users", list);
    return "index";
}

在 index.html中显示

<table>
    <tr>
        <th>用户名</th>
        <th>操作</th>
    </tr>
    <tr th:each="user:${users}">
        <td th:text="${user.username}"></td>
        <td><a th:href="@{/kickout(username=${user.username})}">下线</a></td>
    </tr>
</table>

3)增加踢人接口

@GetMapping("/kickout")
public String kickout(String username) {
    List<Object> allPrincipals = sessionRegistry.getAllPrincipals();
    for (Object principal : allPrincipals) {
        List<SessionInformation> allSessions = sessionRegistry.getAllSessions(principal, false);
        User user = (User) principal;
        if (user.getUsername().equals(username)) {
            //将所有已登录的 session 都失效
            allSessions.forEach(SessionInformation::expireNow);
        }
    }
    return "redirect:/index";
}

6、允许跨域处理

什么是跨域

CORS跨域,全称是“跨域资源共享”(Cross-Origin Resource Sharing),是一种基于HTTP标头的机制,它允许服务器指示除其自身之外的任何来源(域、方案或端口),浏览器应允许从中加载资源。这种机制允许浏览器向跨源服务器发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

当浏览器从一个源(域)向另一个源(域)发出请求时,由于安全原因,浏览器会限制这种跨源请求。但是,CORS通过服务器和浏览器的协商,允许某些跨源请求得以通过。具体来说,浏览器会先向服务器发送一个“预检”请求,检查服务器是否允许实际请求。如果服务器允许,那么浏览器就会发送实际的跨域请求。

CORS需要浏览器和服务器同时支持,目前几乎所有的浏览器都支持CORS,但IE浏览器不能低于IE10版本。实现CORS的关键在于服务器,只要服务器实现了CORS接口,就可以实现跨域通信。

Spring Security 配置允许跨域

配置 HttpSecurity

// 开启跨域
http.cors(Customizer.withDefaults())

7、跨域攻击防护

什么是CSRF

CSRF,全称是跨站请求攻击(Cross-Site Request Forgery),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。简单来说,攻击者通过一些技术手段欺骗用户的浏览器去访问一个用户之前已经认证过的站点,并运行一些操作,如发邮件、发消息,甚至进行财产操作(如转账和购买商品)等。由于浏览器之前已经认证过,被访问的站点会误以为是真正的用户操作而去运行。这种攻击利用了Web中用户身份认证验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。因此,CSRF攻击可以被理解为攻击者盗用了用户的身份,以用户的名义发送恶意请求。

为了防范CSRF攻击,Web应用程序可以采取一些措施,如使用验证码、检查请求来源、使用CSRF令牌等。这些措施可以增加攻击的难度,降低攻击成功的可能性。同时,用户也应该保持警惕,不要随意点击不明链接或下载未知来源的文件,以保护自己的隐私和财产安全。

Spring Security 处理 CSRF

默认情况下,Spring Security 会自动启用 CSRF 保护,这包括在表单中包含 CSRF 令牌(token)并在处理请求时验证这个令牌。

// 开启csrf 保护
http.csrf(Customizer.withDefaults());

在登录表单中,会自动生成参数_csrf ,如下所示:

在这里插入图片描述

参考

  • https://docs.spring.io/spring-security/reference/index.html

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT调教指南 | 咒语指南 | Prompts提示词教程(二)

在我们开始探索人工智能的世界时&#xff0c;了解如何与之有效沉浸交流是至关重要的。想象一下&#xff0c;你手中有一把钥匙&#xff0c;可以解锁与OpenAI的GPT模型沟通的无限可能。这把钥匙就是——正确的提示词&#xff08;prompts&#xff09;。无论你是AI领域的新手&#…

flinksql 流表转换, 自定义udf/udtf,SQL 内置函数及自定义函数

flinksql 流表转换&#xff0c; 自定义udf/udtf 1、标量函数2、表函数3、聚合函数4、表聚合函数 1、在大多数情况下&#xff0c;用户定义的函数必须先注册&#xff0c;然后才能在查询中使用。不需要专门为 Scala 的 Table API 注册函数。 2、函数通过调用 registerFunction&am…

yolov9目标检测报错AttributeError: ‘list‘ object has no attribute ‘device‘

最近微智启软件工作室在运行yolov9目标检测的detect.py测试代码时&#xff0c;报错&#xff1a; File “G:\down\yolov9-main\yolov9-main\detect.py”, line 102, in run pred non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_detmax_det) Fil…

Python urllib、requests、HTMLParser

HTTP协议 HTTP 协议&#xff1a;一般指HTTP(超文本传输)协议。 HTTP是为Web浏览器和Web服务器之间的通信而设计的&#xff0c;基于TCP/IP通信协议嘞传递数据。 HTTP消息结构 客户端请求消息 客户端发送一个HTTP请求到服务器的请求消息包括以下格式 请求行(request line)请求…

排序算法之——归并排序

归并排序 1. 基本思想2. 数据的分解3. 数据的合并4.归并排序的实现4.1 递归实现4.1.1 一个易错点4.1.2 运行结果 4.2 非递归实现4.2.1 图示思路4.2.2 代码实现4.2.3 一个易错点4.2.4 修改后的代码4.2.5 运行结果 6. 时间复杂度7. 空间复杂度8. 稳定性9. 动图演示 1. 基本思想 …

h-table(表格列表组件的全封装)

文章目录 概要h-table的封装过程查询组件封装 h-highForm结果页右侧工具栏封装RightToolbar结果页列表组件h-table结果页vue页面使用js文件有需要的请私信博主&#xff0c;还请麻烦给个关注&#xff0c;博主不定期更新组件封装&#xff0c;或许能够有所帮助&#xff01;&#x…

如何用GPT进行成像光谱遥感数据处理?

第一&#xff1a;遥感科学 从摄影侦察到卫星图像 遥感的基本原理 遥感的典型应用 第二&#xff1a;ChatGPT ChatGPT可以做什么&#xff1f; ChatGPT演示使用 ChatGPT的未来 第三&#xff1a;prompt 提示词 Prompt技巧&#xff08;大几岁&#xff09; 最好的原则和策…

互动游戏团队如何将性能体验优化做到TOP级别

一、背景 随着互动游戏业务 DAU 量级增加&#xff0c;性能和体验重要性也越发重要&#xff0c;好的性能和体验不仅可以增加用户使用体感&#xff0c;也可以增加用户对于互动游戏的使用粘性。 对现状分析&#xff0c;主要存在首屏渲染速度慢、打开页面存在白屏、页面加载过多资…

app测试必掌握的核心测试:UI、功能测试!

一、UI测试 UI即User Interface (用户界面)的简称。UI 设计则是指对软件的人机交互、操作逻辑、界面美观的整体设计。好的UI设计不仅是让软件变得有个性有品味,还要让软件的操作变得舒适、简单、自由、充分体现软件的定位和特点。手机APP从启动界面开始, 到运行过程,直至退出,…

聊聊mysql的七种日志

进入正题前,可以先简单介绍一下,MySQL的逻辑架构, MySQL的逻辑架构大致可以分为三层: 第一层:处理客户端连接、授权认证,安全校验等。第二层:服务器 server 层,负责对SQL解释、分析、优化、执行操作引擎等。第三层:存储引擎,负责MySQL中数据的存储和提取。我们要知道…

云图极速版限时免费活动

产品介绍 云图极速版是针对拥有攻击面管理需求的用户打造的 SaaS 应用&#xff0c;致力于协助用户发现并管理互联网资产攻击面。 实战数据 (2023.11.6 - 2024.2.23) 云图极速版上线 3 个月以来&#xff0c;接入用户 3,563 家&#xff0c;扫描主体 19,961 个&#xff0c;累计发…

OpenCV笔记4:级联分类器实现嘴部检测

OpenCV 嘴部检测 """ 嘴部区域检测 1. 静态图像检测嘴部区域创建分类器加载特征文件检测图像绘制嘴部区域显示 2. 切换为摄像头 """ import cv2 import numpy as npclass FaceDetect:def __init__(self):# 级联分类器# 创建级联分类器&#xf…

云原生之容器管理工具Portainer

1. 简介 前面文章我们讲Docker、Docker Compose和Docker Swarm都是在Linux系统上手工命令行去操作&#xff0c;在第一次安装的时候可以命令行&#xff0c;以后运维和CICD流程操作中&#xff0c;如果还要命令行去各个节点操作&#xff0c;操作就麻烦了&#xff0c;工作效…

Seata 入门知识

目录 概述 工作流程 工作模式 AT模式 TCC模式 概述 Seata 是一款开源的分布式事务解决方案&#xff0c;致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式&#xff0c;为用户打造一站式的分布式解决方案。 AT模式是阿里首推…

Linux系统运维:离线安装sar-性能监视和分析工具

目 录 一、前言 二、系统环境 三、安装sar &#xff08;一&#xff09;准备工作 1、下载 sar 工具的安装包&#xff1a; 2、将安装包传输到 CentOS 服务器 &#xff08;二&#xff09;安装工作 1、解压 2、配置安装 3、编译 4、安装 &#xff08;三&#xff0…

C# Onnx 使用onnxruntime部署实时视频帧插值

目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx 使用onnxruntime部署实时视频帧插值 介绍 github地址&#xff1a;https://github.com/google-research/frame-interpolation FILM: Frame Interpolation for Large Motion, In ECCV 2022. The official Tensorflow 2…

【Flink集群RPC通讯机制(四)】集群组件(tm、jm与rm)之间的RPC通信

文章目录 1. 集群内部通讯方法概述2. TaskManager向ResourceManager注册RPC服务3. JobMaster向ResourceManager申请Slot计算资源 现在我们已经知道Flink中RPC通信框架的底层设计与实现&#xff0c;接下来通过具体的实例了解集群运行时中组件如何基于RPC通信框架构建相互之间的调…

大数据 - Spark系列《十一》- Spark累加器详解

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 大数据 - Spark系列《三》- 加载各种数据源创建RDD-CSDN博客 大数据 - Spark系列《…

2024/02/23

使用消息队列完成两个进程间相互通信 A.c #include<myhead.h> struct msgbuf {long mtype;char mtext[1024]; }; //定义表示正文内容大小的宏 #define MSGSIZE sizeof(struct msgbuf)-sizeof(long)int main(int argc, const char *argv[]) {//创建一个key值key_t key;ke…

知乎66条高赞回答,句句醍醐灌顶!

-01- 穷人是小心翼翼地大方&#xff0c; 有钱人是大大方方地小气。 ——论如何判断一个人是真有钱还是装有钱 -02- 枕头要常晒&#xff0c; 因为里面装满了心酸的泪和发霉的梦。 ——一切终将随风而逝 -03- 人活得累&#xff0c;一是太认真&#xff0c;二是太想要。 …