Springboot +spring security,前后端分离时的security处理方案(二)

news2024/12/29 10:29:40

一.简介

在前后端分离这样的开发模式下,前后端的交互都是通过 JSON 来进行数据传递的,无论登录成功还是失败,都不会有服务端跳转或者客户端跳转之类的操作。

也就是说无论登录成功还是失败,服务端都会返回一段登录成功或失败的 JSON 信息给前端,前端收到JSON之后来决定是该跳转到成功界面还是失败界面,和后端没有关系。

二.认证处理时的相关API

2.1页面跳转的相关API

2.1.1登录成功时的跳转API

表单认证时,处理登录成功时,跳转到某个页面的API是如下两个方法:

  1. defaultSuccessUrl
  2. successForwardUrl

以上两个方法都是用来配置跳转地址的,适用于前后端不分离时的开发。

2.1.2登录失败时的跳转API

处理登录失败时,跳转页面的API是如下两个方法:

  1. failureUrl()
  2. failureForwardUrl()

以上两个方法也是用来配置跳转地址的,同样适用于前后端不分离时的开发。

2.2返回JSON格式的处理器

上面的两类方法,无论是认证成功还是认证失败,都是在前后端不分离时的处理方案,直接从Java后端跳转到某个页面上。那么在前后端分离时,Java后端项目中,根本就没有页面。

在前后端分离模式下,既然后端没有页面,页面都在前端,那就可以考虑使用JSON来进行信息交互了,我们把认证成功或认证失败的信息,以JSON的格式传递给前端,由前端来决定到底该往哪个页面跳转就好了。

如果要返回JSON格式的信息,有如下相关方法:

  1. successHandler()
  2. failureHandler()
  3. logoutSuccessHandler()
  4. authenticationEntryPoint()

三. 创建SpringSecurity项目

参考之前的文章,这边不做叙述。

四. 认证成功时的处理方案

首先看下相关的方法及其核心参数,即successHandler()和onAuthenticationSuccess参数。

4.1successHandler()方法

**successHandler()**方法的功能十分强大,囊括了 defaultSuccessUrl()和 successForwardUrl() 的功能。

**successHandler()**方法的参数是一个 AuthenticationSuccessHandler 对象,这个对象中我们要实现的方法是 onAuthenticationSuccess()。

4.2onAuthenticationSuccess参数

onAuthenticationSuccess() 方法中有三个参数,分别是:

  1. HttpServletRequest: 利用该参数我们可以实现服务端的跳转;
  2. HttpServletResponse: 利用该参数我们可以做客户端的跳转,也可以返回 JSON 数据;
  3. Authentication: 这个参数则保存了我们刚刚登录成功的用户信息。

4.3定义SecurityAuthenticationSuccessHandler类

了解完主要的方法和参数之后,我们先来编写一个处理器类,该类需要实现SavedRequestAwareAuthenticationSuccessHandler接口。
代码如下:

/**
 * 处理登录成功时的业务逻辑
 */
public class SecurityAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
 
    /**
     * Authentication:携带登录的用户名及角色等信息
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        //直接输出json格式的响应信息
        Object principal = authentication.getPrincipal();
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        //以json格式对外输出身份信息
        out.write(new ObjectMapper().writeValueAsString(principal));
        out.flush();
        out.close();
    }
}

4.4配置successHandler

然后在SecurityConfig配置类中,调用successHandler()方法,把前面定义的SecurityAuthenticationSuccessHandler类关联进来。代码如下:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll()
                //认证成功时的处理器
                .successHandler(new SecurityAuthenticationSuccessHandler())
                .and()
                .csrf()
                .disable();
    }
 
}

4.5验证

配置完成后,进行登录验证,在认证成功后,就可以看到登录成功的用户信息是通过 JSON 返回到前端的,如图所示:
在这里插入图片描述
在认证成功后,Spring Security会把认证的用户信息以JSON格式展示出来,比如用户名、密码、角色等信息。

五.认证失败时的处理方案

如何实现认证失败时的处理方案,同样的,先看下相关的API方法及参数。

5.1failureHandler()

failureHandler()方法的参数是一个 AuthenticationFailureHandler 对象,这个对象中我们要实现的方法是 onAuthenticationFailure()。

onAuthenticationFailure()方法有三个参数,分别是:

  1. HttpServletRequest: 利用该参数我们可以实现服务端的跳转;
  2. HttpServletResponse: 利用该参数我们可以做客户端的跳转,也可以返回 JSON 数据;
  3. AuthenticationException: 这个参数则保存了登录失败的原因。

5.2定义SecurityAuthenticationFailureHandler类

SecurityAuthenticationFailureHandler类的代码如下:

/**
 * 处理登录失败时的业务逻辑
 */
public class SecurityAuthenticationFailureHandler extends ExceptionMappingAuthenticationFailureHandler {
 
    /**
     * AuthenticationException:异常信息
     */
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        //直接输出json格式的响应信息
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(e.getMessage());
        out.flush();
        out.close();
    }
}

5.3配置failureHandler

接着在SecurityConfig配置类中,调用failureHandler()方法来关联上面定义的SecurityAuthenticationFailureHandler类对象。代码如下:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll()
                //认证成功时的处理器
                .successHandler(new SecurityAuthenticationSuccessHandler())
                //认证失败时的处理器
                .failureHandler(new SecurityAuthenticationFailureHandler())
                .and()
                .csrf()
                .disable();
    }
 
}

5.4验证

配置完成后,再去登录,在认证失败时,就可以看到登录失败的用户信息通过 JSON 返回到前端了,如下图所示:
在这里插入图片描述

六.退出登录时的处理方案

实现了认证成功和认证失败后的处理方案后,接下来看下如何处理退出登录。

6.1logoutSuccessHandler()

负责退出登录的方法是logoutSuccessHandler(),这个方法中需要一个参数LogoutSuccessHandler;在LogoutSuccessHandler类中有一个方法 onLogoutSuccess(),该方法中的参数与登录成功时的参数一样。

6.2定义SecurityLogoutSuccessHandler类

SecurityLogoutSuccessHandler类的代码如下:

public class SecurityLogoutSuccessHandler implements LogoutSuccessHandler {
 
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write("注销成功");
        out.flush();
        out.close();
    }
 
}

6.3 配置logoutSuccessHandler

在SecurityConfig配置类中,调用logoutSuccessHandler()方法来关联上面定义的SecurityLogoutSuccessHandler对象。代码如下:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll()
                //认证成功时的处理器
                .successHandler(new SecurityAuthenticationSuccessHandler())
                //认证失败时的处理器
                .failureHandler(new SecurityAuthenticationFailureHandler())
                .and()
                .logout()
                //退出登录时的处理器
                .logoutSuccessHandler(new SecurityLogoutSuccessHandler())
                .and()
                .csrf()
                .disable();
    }
 
}

6.4验证

配置完成后,我们去访问/logout接口,退出登录成功,截图如下:
在这里插入图片描述

七.未认证时的处理方案

接下来看下如何处理未认证时的方案。

大体思路:
如果用户没有登录,就访问一个需要认证后才能访问的页面。这个时候,我们不应该让用户重定向到登录页面,而是给用户一个尚未登录的提示,前端收到提示之后,再自行决定页面跳转。因为在前后端分离时,后端没有页面,未认证时也没办法直接重定向到登录页面啊!

7.1authenticationEntryPoint()

未认证时,同样有个专门的方法来处理,即authenticationEntryPoint()方法,这个方法中需要一个参数LoginUrlAuthenticationEntryPoint,在LoginUrlAuthenticationEntryPoint类中有一个方法 commence()。

7.2定义SecurityAuthenticationEntryPoint类

SecurityAuthenticationEntryPoint类的代码如下:

public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
 
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write("尚未登录,请先登录");
        out.flush();
        out.close();
    }
 
}

7.3 配置authenticationEntryPoint

在SecurityConfig配置类中,调用authenticationEntryPoint()方法来关联上面定义的SecurityAuthenticationEntryPoint对象。代码如下:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll()
                //认证成功时的处理器
                .successHandler(new SecurityAuthenticationSuccessHandler())
                //认证失败时的处理器
                .failureHandler(new SecurityAuthenticationFailureHandler())
                .and()
                .csrf()
                .disable()
                .exceptionHandling()
                //未登录时的处理器
                .authenticationEntryPoint(new SecurityAuthenticationEntryPoint());
    }
 
}

7.4验证

配置完成后,在未登录时,直接去访问项目中的某个接口,就会看到未登录时返回的JSON信息,截图如下:
在这里插入图片描述

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

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

相关文章

Go 1.19 排序算法

插入排序(InsertionSort) 插入排序是一种简单直观的排序算法,它的基本思想是将待排序的元素插入到已经排好序的序列中,从而得到一个新的有序序列。插入排序的具体过程如下: 从第一个元素开始,认为它已经是…

RK3568 i2s TDM数据抓取

1. I2S接口 I2S协议只定义三根信号线:时钟信号SCK、串行数据信号SD、左右声道选择信号WS。 SCK 时钟信号,Serial Clock,也可能称BCLK/Bit Clock或SCL/Serial Clock。 WS 左右声道选择信号,Word Select,也称帧时钟,也可能称LRCLK/Left Right Clock。 SD 串行数据信号,Ser…

计算机网络第一章——计算机网络系统结构(下)

提示:总角之宴,言笑晏晏。信誓旦旦,不思其反。反是不思,亦已焉哉。 文章目录 1.2.1 分层结构,协议,接口和服务为什么要有分层?怎么分层正式认识分层结构概念总结 1.2.2 OSI 参考模型ISO参考模型…

Markdown 格式文章的图床

chatGPT 奖励模型示意图: chatGPT RLHF(基于人类反馈的强化学习) 模型示意图: 强化学习过程示意图:

《HashMap的数据结构》

目录 HashMap概述&#xff1a; 数据结构的组成&#xff1a; 一个键值对是如何存入该结构中&#xff1a; HashMap中链表和红黑树的用途和转换方式 &#xff1a; HashMap概述&#xff1a; HashMap是基于哈希表的Map接口实现的&#xff0c;它存储的内容是键值对<key,value&g…

Web安全:文件包含漏洞测试(防止 黑客利用此漏洞.)

Web安全&#xff1a;文件包含漏洞测试. 文件包含的漏洞是 程序员在开发网站的时候&#xff0c;为了方便自己开发构架&#xff0c;使用了一些包含的函数&#xff08;比如&#xff1a;php开发语言&#xff0c;include() , include_once() , require_once() 等等 &#xff09;&a…

书单 | 数据治理的30本书

随着数字经济时代的到来&#xff0c;数据的价值不断被发掘。党的十九届四中全会首次将“数据”列为生产要素&#xff0c;充分凸显了数字经济时代数据对于经济活动和社会生活的巨大价值。开展数据治理的理论探索和实践创新&#xff0c;有利于全面释放数据价值助力数字经济发展&a…

校园高校共享单车管理系统nodejs+vue+express

设计的管理员的详细功能见下图&#xff0c;管理员登录进入本人后台之后&#xff0c;管理单车和区域&#xff0c;审核租赁订单和还车订单&#xff0c;收取租赁费用&#xff0c;查看单车租赁统计信息。 vue的文件结构其实就是一个index.html 中间的内容&#xff0c;用的是vue&am…

代码随想录算法训练营第二十二天|235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作 、450.删除二叉搜索树中的节点

二叉搜索树的最近公共祖先 题目链接&#xff1a;力扣 其实可以用之前普通二叉树最近公共祖先的算法。但是这样没有很好的利用二叉搜索树是有序的性质。 TreeNode* lowestCommonAncestor1(TreeNode* root, TreeNode* p, TreeNode* q) {if(!root || root p ||rootq) return roo…

嵌入式系统中重要的编程思想:分层与时间片

1. 分层思想 分层的思想&#xff0c;并不是什么神秘的东西&#xff0c;事实上很多做项目的工程师本身自己也会在用。分层结构确是很有用的东西&#xff0c;参透后会有一种恍然大悟的感觉。 如果说我不懂LCD怎么驱动&#xff0c;那好办&#xff0c;看一下datasheet&#xff0c…

Java技术规范概览

Java技术规范 目录概述需求&#xff1a; 设计思路实现思路分析1.Java JSR的部分2.JSR-000373.JSR-0000394.JSR-000337 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a bet…

三步快速激活chatGPT4

0、背景 Depay停止注册背景下&#xff0c;新用户如何开通chatGPT4&#x1f914;? 注意事项; 1.选在8:00-22:00之间阅读本教程&#x1f600;&#x1f601;&#x1f604; 2.本教程尝试过欧易和nodepay&#xff0c;但都不好用&#xff0c;故采用FOMEpay&#x1f60d;&#x1f60…

#Microsoft Edge功能测评!# 关于Edge浏览器以及插件推荐

关于Edge浏览器以及插件推荐 1.关于Microsoft Edge......1.1 什么是Microsoft Edge1.2Microsoft Edge的优势 2.Microsoft Edge的分屏功能2.1 如何分屏&#xff1f;2.2分屏的优势 3.Microsoft Edge插件推荐3.1 AIX智能下载器(图片/视频/音乐/文档)3.2 AdGuard 广告拦截器3.3 破解…

python基础知识(五):while循环、for循环、continue语句和break语句

目录 1. while循环2. for循环3. 循环语句和if语句结合3. continue语句4. break语句5. 双重循环6. 双重循环和continue语句以及break语句 1. while循环 while循环简单来说就是满足循环条件就执行循环语句&#xff0c;直到不满足为止&#xff0c;否则陷入死循环。 while语法 wh…

[架构之路-202]- 常见的需求获取技术=》输出=》用户需求、客户需求(As...., I want.....)、用例图

目录 前言&#xff1a; 11.2.1 直接的用户访谈 1 . 准备访谈 2 . 访谈过程 3 . 访谈的后续工作 4 . 用户访谈的优缺点 11.2.2 问卷调查 1 . 调查表的制作 2 . 问卷调查的优缺点 3 . 提高问卷返还率的方法 11.2.3 采样 1 . 样本大小 2 . 采样的优缺点 11.2.4 情节…

路径规划算法:基于生物地理学优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于生物地理学优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于生物地理学优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能…

上海亚商投顾:上证50创年内新低 电力、煤炭板块全天领跌

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日震荡调整&#xff0c;午后集体跌超1%&#xff0c;上证50一度跌近2%&#xff0c;尾盘跌幅有所收窄。芯…

MyBatis——动态SQL

经常遇到很多按照很多查询条件进行查询的情况&#xff0c;比如京东根据不同的条件筛选商品。其中经常出现很多条件不取值的情况&#xff0c;在后台应该如何完成最终的SQL语句呢&#xff1f; 如果采用JDBC进行处理&#xff0c;需要根据条件是否取值进行SQL语句的拼接&#xff0…

05 缓存预热+缓存雪崩+缓存击穿+缓存穿透

缓存血崩 发生 redis主机挂了&#xff0c;Redis 全盘崩溃比如缓存中有大量数据同时过期 解决 redis缓存集群实现高可用 主从哨兵Redis Cluster ehcache本地缓存 Hystrix或者阿里sentinel限流&降级开启Redis持久化机制aof/rdb&#xff0c;尽快恢复缓存集群 缓存穿透 是…

Gouraud Shading(高洛德着色法)和其优缺点详解

​ Gouraud是一种插值方法&#xff0c;Gouraud着色法是计算机图形学中的一种插值方法&#xff0c;可以为多边形网格表面生成连续的明暗变化。实际使用时&#xff0c;通常先计算三角形每个顶点的光照&#xff0c;再通过双线性插值计算三角形区域中其它像素的颜色。 在图形处理器…