Spring Security实现用户认证二:前后端分离时自定义返回Json内容

news2025/1/24 22:38:49

Spring Security实现用户认证二:前后端分离时自定义返回Json内容

  • 1 前后端分离
  • 2 准备工作
    • 依赖
    • WebSecurityConfig配置类
  • 2 自定义登录页面
    • 2.1 Spring Security的默认登录页面
    • 2.2 自定义配置formLogin
  • 3 自定义登录成功处理器
  • 4 自定义登录失败处理器
  • 5 自定义登出处理器
  • 6 自定义回话过期处理器
  • 7 定义认证失败接入点

1 前后端分离

在现在大多数web开发中,采用的开发模式均是前后端分离类型的。往往后端给前端返回的数据格式为json类型:

{
	"code":"200",
	"message":"success",
	"data":"登录成功"
}

2 准备工作

依赖

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

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

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

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity6</artifactId>
</dependency>

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
</dependency>

WebSecurityConfig配置类

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
	//为存储在内存中的基于用户名/密码的认证提供支持。
    @Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withDefaultPasswordEncoder().username("root").password("root").roles("USER").build());
        return manager;
    }


    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

//        ResultData<String> result = ResultData.success("登录成功");
        Map<String, Object> result = new HashMap<>();
        result.put("code", "200");
        result.put("message", "登录成功");
        result.put("data", "");

        //将结果转换成字符串
        String json = JSON.toJSONString(result);

        //返回json数据
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
    }
}

2 自定义登录页面

2.1 Spring Security的默认登录页面

.httpBasic(withDefaults())
在这里插入图片描述
.formLogin(withDefaults())
在这里插入图片描述

2.2 自定义配置formLogin

注释掉原来的formLogin和httpBasic。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.authorizeRequests(authorize ->
                    authorize
                            .anyRequest()
                            .authenticated()
            );
//                .formLogin(withDefaults())
//                .httpBasic(withDefaults());

    http.formLogin(login ->
             login.loginPage("/login").permitAll() // 一定加上这个,不然会一直重定向,导致报错
    );

    return http.build();
}

在resources下创建目录templates,用来存放thymeleaf写的页面,在这个目录下面创建login.html页面

<html xmlns:th="https://www.thymeleaf.org">
<head>
    <title>login</title>
</head>
<body>
<h1>Login</h1>
<div th:if="${param.error}">错误的用户名或密码.
</div>
<form th:action="@{/login}" method="post">
    <div>
        <input type="text" name="username" placeholder="请输入用户名">
    </div>
    <div>
        <input type="password" name="password" placeholder="请输入密码">
    </div>
    <input type="submit" value="登录">
</form>
</body>
</html>

创建LoginController :

@GetMapping("/login")
public String login(){
    return "login";
}

效果如下:
在这里插入图片描述

3 自定义登录成功处理器

定义MyAuthenticationSuccessHandler

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {

        Map<String, Object> result = new HashMap<>();
        result.put("code", "200");
        result.put("message", "登录成功");
        result.put("data", "");

        //将结果转换成字符串
        String json = JSON.toJSONString(result);

        //返回json数据
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
    }
}

添加配置

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	// ...

    http.formLogin(login -> {
        login.loginPage("/login").permitAll();
        login.successHandler(new MyAuthenticationSuccessHandler());
    });

    return http.build();
}

效果
在这里插入图片描述

4 自定义登录失败处理器

定义MyAuthenticationFailureHandler

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("code", "401");
        result.put("message", "登录失败");
        result.put("data", "");

        //将结果转换成字符串
        String json = JSON.toJSONString(result);

        //返回json数据
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
    }
}

添加配置

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	// ...

    http.formLogin(login -> {
            login.loginPage("/login").permitAll();
            login.successHandler(new MyAuthenticationSuccessHandler());
            login.failureHandler(new MyAuthenticationFailureHandler());
    });

    return http.build();
}

效果
在这里插入图片描述

5 自定义登出处理器

定义MyLogoutSuccessHandler

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("code", "200");
        result.put("message", "登出成功");
        //将结果转换成字符串
        String json = JSON.toJSONString(result);

        //返回json数据
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
    }
}

添加配置

为了能够正确登出,需要将csrf配置关闭,否则只接受post请求登出。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	// ...
    http.logout(logout -> {
         logout.logoutSuccessHandler(new MyLogoutSuccessHandler());
    });


	http.csrf(csrf->csrf.disable());
	
    return http.build();
}

效果
在这里插入图片描述

6 自定义回话过期处理器

这个当会话过期或者超出登录数量时。

定义MyLogoutSuccessHandler

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("code", "200");
        result.put("message", "登出成功");
        //将结果转换成字符串
        String json = JSON.toJSONString(result);

        //返回json数据
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
    }
}

添加配置

将最大的session数限制为1,则只允许一个session在线。expiredSessionStrategy指定过期策略。

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	// ...
	    http.sessionManagement(session ->{
	          session.maximumSessions(1).expiredSessionStrategy(new MySessionInformationExpiredStrategy());
        });
	
    return http.build();
}

先登录一个浏览器,在登录另一个浏览器,在刷新第一个浏览器。
效果
在这里插入图片描述

7 定义认证失败接入点

创建:MyAuthenticationEntryPoint 实现 AuthenticationEntryPoint接口

import com.alibaba.fastjson2.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        String localizedMessage = authException.getLocalizedMessage();

        Map<String, Object> result = new HashMap<>();
        result.put("code", "500");
        result.put("message", localizedMessage);

        String jsonString = JSON.toJSONString(result);

        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(jsonString);

    }
}


配置WebSecurityConfig:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
	// ...
    http.exceptionHandling(exception ->{
           exception.authenticationEntryPoint(new MyAuthenticationEntryPoint());
    });
    return http.build();
}

在我们没有登录时。直接访问主页,会发生异常。

效果
在这里插入图片描述

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

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

相关文章

5万字带你一文看懂自动驾驶之高精度地图前世今生

在讲解高精度地图之前&#xff0c;我们先把定位这个事情弄清楚&#xff0c;想明白&#xff0c;后面的事情就会清晰很多&#xff0c;自古哲学里面讨论的人生终极问题&#xff0c;无非就三个&#xff0c;我是谁&#xff0c;我从哪里来&#xff0c;我要去哪里&#xff0c;这里的位…

语言模型测试系列【8】

语言模型 文心一言星火认知大模型通义千问豆包360智脑百川大模型腾讯混元助手Kimi Chat商量C知道 这次的测试比较有针对性&#xff0c;是在使用钉钉新推出的AI助理功能之后发现的问题&#xff0c;即创建AI助理绑定自己钉钉的知识库进行问答&#xff0c;其中对于表结构的文档学…

Vue3商城后台管理实战-用户登录界面设计

界面设计 此时界面的预览效果如下&#xff1a; 登录界面的完整代码如下&#xff1a; <script setup> import {reactive} from "vue/reactivity";const form reactive({username: "",password: "", })const onSubmit () > {} <…

多点 Dmall x TiDB:出海多云多活架构下的 TiDB 运维实战

作者&#xff1a;多点&#xff0c;唐万民 导读 时隔 2 年&#xff0c; 在 TiDB 社区成都地区组织者冯光普老师的协助下&#xff0c;TiDB 社区线下地区活动再次来到成都。来自多点 Dmall 的国内数据库负责人唐万民老师&#xff0c;在《出海多云架构&#xff0c;多点 TiDB 运维…

【class9】人工智能初步(处理单张图片)

Class9的任务&#xff1a;处理单张图像 为了更高效地学习&#xff0c;我们将“处理单张图像”拆分成以下几步完成&#xff1a; 1. 读取图像文件 2. 调用通用物体识别 3. 提取图像分类信息 4. 对应分类文件夹还未创建时&#xff0c;创建文件夹 5. 移动图像到对应文件夹 0.获取…

Qt---TCP文件传输服务器

文件传输流程&#xff1a; 服务器端&#xff1a; serverwidget.ui serverwidget.h #ifndef SERVERWIDGET_H #define SERVERWIDGET_H#include <QWidget> #include<QTcpServer>//监听套接字 #include<QTcpSocket>//通信套接字 #include<QFile> #includ…

查看Linux系统是Ubuntu还是CentOS

要查看Linux系统是Ubuntu还是CentOS&#xff0c;可以通过多种方式进行确认&#xff1a; 查看/etc/os-release文件&#xff1a; 在终端中执行以下命令&#xff1a; cat /etc/os-release 如果输出中包含"IDubuntu"&#xff0c;则表示系统是Ubuntu&#xff1b;如果输出中…

构建智能电子商务系统:数字化引领未来商业发展

随着互联网技术的飞速发展和消费者行为的变革&#xff0c;电子商务系统的重要性日益凸显。在这一背景下&#xff0c;构建智能电子商务系统成为推动商业数字化转型的关键举措。本文将深入探讨智能电子商务系统的构建与优势&#xff0c;助力企业把握数字化转型的主动权。 ### 智…

【Linux】19. 习题②

2022-11-12_Linux环境变量 1. 分页存储(了解) 一个分页存储管理系统中&#xff0c;地址长度为 32 位&#xff0c;其中页号占 8 位&#xff0c;则页表长度是__。 A.2的8次方 B.2的16次方 C.2的24次方 D.2的32次方 【答案解析】A 页号即页表项的序号&#xff0c;总共占8个二进制…

数字化智能:Web3时代的物联网创新之路

引言 随着科技的不断发展&#xff0c;物联网&#xff08;IoT&#xff09;技术正在迅速普及和应用。而随着Web3时代的到来&#xff0c;物联网将迎来新的发展机遇和挑战。本文将探讨Web3时代的物联网创新之路&#xff0c;深入分析其核心技术、应用场景以及未来发展趋势。 Web3时…

C语言性能深度剖析:从底层优化到高级技巧及实战案例分析

C语言以其接近硬件的特性、卓越的性能和灵活性&#xff0c;在系统编程、嵌入式开发和高性能计算等领域中占据着举足轻重的地位。本文将深入探讨C语言性能优化的各个方面&#xff0c;包括底层原理、编译器优化、内存管理和高级编程技巧&#xff0c;并结合多个代码案例来具体分析…

2024042002-计算机网络 - 应用层

计算机网络 - 应用层 计算机网络 - 应用层 域名系统文件传送协议动态主机配置协议远程登录协议电子邮件协议 1. SMTP2. POP33. IMAP 常用端口Web 页面请求过程 1. DHCP 配置主机信息2. ARP 解析 MAC 地址3. DNS 解析域名4. HTTP 请求页面 域名系统 DNS 是一个分布式数据库&…

ApiHug - 闭门造车, 出门合辙

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace The Nex…

Python函数之旅专栏(导航)

Python内置函数(参考版本:3.11.8)AELRabs( )enumerate( )len( )range( )aiter( )eval( )list( )repr( )all( )exec( )locals( )reversed( )anext( )round( )any( ) ascii( )FM  filter( )map( )S float( )max( )set( )Bformat( )memoryview( )setattr( )bin( )frozenset( )…

TensorFlow的学习

0.基础概念 术语表&#xff1a; https://developers.google.cn/machine-learning/glossary?hlzh-cn#logits 1.快速入门 https://tensorflow.google.cn/tutorials/quickstart/beginner?hlzh-cn 2.基于Keras进行图像分类 https://tensorflow.google.cn/tutorials/keras/cl…

SMB攻击利用之-mimikatz上传/下载流量数据包逆向分析

SMB协议作为windows环境下最为常见的一种协议,在历史上出现过无数的通过SMB协议进行网络攻击利用的案例,包括针对SMB协议本身以及通过SMB协议实施网络攻击。 本文将介绍一种通过SMB协议的常见利用方式,即向远程主机传输mimikatz,作为我的专栏《SMB攻击流量数据包分析》中的…

【Python】图像批量合成视频,并以文件夹名称命名合成的视频

一个文件夹中有多个子文件夹&#xff0c;子文件夹中有多张图像。如何把批量把子文件夹中的图像合成视频&#xff0c;视频名称是子文件夹的名称&#xff0c;生成的视频保存到指定文件夹&#xff0c;效果记录。 代码 import os import cv2def create_video_from_images(image_f…

Mamba:7 VENI VIDI VICI

若在阅读过程中有些知识点存在盲区&#xff0c;可以回到如何优雅的谈论大模型重新阅读。另外斯坦福2024人工智能报告解读为通识性读物。若对于如果构建生成级别的AI架构则可以关注AI架构设计。技术宅麻烦死磕LLM背后的基础模型。 序列模型的效率与有效性之间的权衡取决于状态编…

[Java基础揉碎]多线程基础

多线程基础 什么是程序, 进程 什么是线程 什么是单线程,多线程 并发, 并行的概念 单核cpu来回切换, 造成貌似同时执行多个任务, 就是并发; 在我们的电脑中可能同时存在并发和并行; 怎么查看自己电脑的cpu有几核 1.资源监视器查看 2.此电脑图标右键管理- 设备管理器- 处理器…

安防监控视频平台智能边缘分析一体机视频存储系统客流统计检测算法

智能边缘分析一体机的客流统计检测算法是一种基于人工智能与边缘计算技术的解决方案&#xff0c;专门设计用来实时、准确地统计通过特定区域的人流量。这项技术广泛应用于零售、交通、场馆管理、智慧城市等领域&#xff0c;以帮助管理者更好地理解顾客行为、优化资源配置、提升…