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

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();
}

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

效果
在这里插入图片描述

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

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

相关文章

如何快速找出文件夹里的全部带有中文纯中文的文件

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 步骤 1、打开工具&#xff0c;切换到批量复制文件 2、鼠标移到右侧&#xff0c;点击搜索添加 3、设定查找范围、指定为文件、勾选 包含全部子文件夹&#x…

254 基于matlab的钢筋混凝土非线性分析

基于matlab的钢筋混凝土非线性分析&#xff0c;根据梁本构关系&#xff0c;然后进行非线性分析&#xff0c;绘制弯矩-曲率曲线。可设置梁的截面尺寸、混凝土本构&#xff0c;钢筋截面面积等相关参数&#xff0c;程序已调通&#xff0c;可直接运行。 254 钢筋混凝土非线性分析 弯…

回文数[简单]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给你一个整数x&#xff0c;如果x是一个回文整数&#xff0c;返回true&#xff1b;否则返回false。回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。例如&#xff0c;121是…

单位个人如何向期刊投稿发表文章?

在单位担任信息宣传员一职以来,我深感肩上的责任重大。每月的对外信息宣传投稿不仅是工作的核心,更是衡量我们部门成效的重要指标。起初,我满腔热血,以为只要勤勉努力,将精心撰写的稿件投至各大报社、报纸期刊的官方邮箱,就能顺利登上版面,赢得读者的青睐。然而,现实远比理想骨…

最小覆盖子串 ---- 滑动窗口

题目链接 题目: 分析: 当我们找到一组符合的子字符串时, 找下一组让left, 那么剩余的子字符串要么还符合条件, 要么少了一种字符, right一定不用回退, 所以可以使用滑动窗口因为题目中说字符串中自包含英文字母, 所以我们可以使用hash数组 定义left 0;right 0;进窗口进窗口…

如何为没有域名的IP地址申请SSL证书

为没有域名的IP地址申请SSL证书的流程相对直接&#xff0c;但需要确保满足一些特定条件。以下是简化的步骤&#xff1a; 1、确保IP地址是公网IP&#xff1a;你必须拥有一个固定的公网IP地址&#xff0c;因为私有IP地址无法用于申请SSL证书。 2、选择证书颁发机构&#xff08;…

什么是Zoho CRM客户关系系统管理?

以客户为中心的商业时代&#xff0c;卓越的客户体验已成为企业持续增长与成功的关键,为了在这场激烈的市场竞争中脱颖而出&#xff0c;企业需要一套强大、灵活且智能的客户关系管理系统——Zoho CRM应运而生&#xff0c;它不仅是管理客户信息的工具箱&#xff0c;更是驱动业务增…

利用远程控制软件FinalShell远程连接虚拟机上的Linux系统(Windows)

一. VMware Workstation 安装CentOS Linux操作系统 传送门&#xff1a;VMware Workstation 安装CentOS Linux操作系统 1.右键打开终端 2.输入ifconfig 找到ens33对应 inet的id&#xff0c;这个就是虚拟机的ip地址图中所示为&#xff1a;192.168.5.128 3.打开finalshell 如…

[ciscn 2022 东北赛区]math

1.题目 import gmpy2 from Crypto.Util.number import * from flag import flag assert flag.startswith(b"flag{") assert flag.endswith(b"}") messagebytes_to_long(flag) def keygen(nbit, dbit):if 2*dbit < nbit:while True:a1 getRandomNBitIn…

渲染农场是什么意思?瑞云渲染为你解答

渲染农场是一种通过集合多台计算机的计算能力来加速图像渲染过程的系统。它尤其适用于动画、电影特效和高端视觉效果的制作&#xff0c;这些领域通常需要处理非常复杂和计算密集型的渲染任务。 渲染农场就是一大群电脑&#xff0c;他们一起可以快速渲染出漂亮的图像。在做动画片…

【Linux进程通信 —— 管道】

Linux进程通信 —— 管道 进程间通信介绍进程间通信的概念进程间通信的目的进程间通信的本质进程间通信的分类 管道什么是管道匿名管道匿名管道的原理pipe用fork来共享管道原理站在文件描述符角度-深度理解管道站在内核角度-管道本质管道读写规则管道的特点管道的四种特殊情况管…

K210开发板MicroPython开发环境搭建

一、安装CanMV IDE开发软件 1、进入如下连接 https://developer.canaan-creative.com/resource 2、点击下载 3、下一步 4、修改安装路径&#xff0c;下一步 5、接受许可下一步 6、下一步 7、安装 8、完成 9、区域①菜单栏&#xff1a;操作文件&#xff0c;使用工具等。…

HCIP【VLAN综合实验】

目录 一、实验拓扑图&#xff1a; 二、实验要求&#xff1a; 三、实验思路&#xff1a; 四、实验步骤&#xff1a; 1、在交换机SW1,SW2,SW3配置VLAN和各个接口对应类型的配置 2、在路由器上面配置DHCP服务 一、实验拓扑图&#xff1a; 二、实验要求&#xff1a; 1、PC1 …

【动态规划五】回文串问题

目录 leetcode题目 一、回文子串 二、最长回文子串 三、分割回文串 IV 四、分割回文串 II 五、最长回文子序列 六、让字符串成为回文串的最少插入次数 leetcode题目 一、回文子串 647. 回文子串 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/…

Linux网络编程——HTTP协议的理解与运用

目录 前言 一、认识URL 二、认识HTTP样例 三、HTTP的报头内容 1.url 2. Content-Type 3.Method 方法 1.GET方法 2.POST方法 4、状态码 5.cookie和session 前言 我们知道&#xff0c;协议就是一种约定&#xff0c;客户端与服务端统一的用这种约定进行传输数据。我们…

deepin V23 RC 正式发布!

deepin 是一款基于 Linux 的开源桌面操作系统&#xff0c;就在今天&#xff0c;deepin V23 RC 来了&#xff0c;欢迎体验与反馈&#xff01; 感谢每一位 deepiner 提供想法与建议&#xff0c;让我们一起为打造美观易用、安全可靠的开源操作系统而努力&#xff01; 重要提示&a…

用docker命令行操作远程的Dockerd daemon服务

本地安装 Dockerd 服务太耗本机磁盘空间了&#xff0c;共用已有的Dockerd服务能够节省一部分空间 修改 Dockerd 服务启动文件&#xff0c;增加TCP监听方式 Dockerd 服务默认监听方式为 Unix Domain Socket &#xff0c;只允许本机连接&#xff0c;想要能够远程连接&#xff0…

一文说通用户故事点数是什么?

一文说通用户故事点数是什么&#xff1f; 第26期&#xff1a;一文说通用户故事点数是什么&#xff1f; 用户故事点数是一种采用相对估算法进行估算的一种工具&#xff0c;一般采用斐波那契数列表征用户故事里说的大小&#xff0c;采用0 1 2 3 5 8 13这样的一些数字来表征用户…

使用人人开源renren-fast快捷搭建后台管理系统

https://gitee.com/renrenio/renren-fast https://gitee.com/renrenio/renren-fast 初始化项目数据库 导入项目运行 期间遇到的坑 024-04-25 01:30:27.638 ERROR 25228 --- [ main] com.alibaba.druid.pool.DruidDataSource : init datasource error, url: jdbc:…

Postman基础功能-接口返回值获取

大家好&#xff0c;之前给大家分享关于Postman的接口关联&#xff0c;我们平时在做接口测试时&#xff0c;请求接口返回的数据都是很复杂的 JSON 数据&#xff0c;有着多层嵌套&#xff0c;这样的数据层级在 Postman 中要怎么获取呢&#xff1f; 接下来给大家展示几个获取 JSO…