[spring] Spring MVC - security(上)

[spring] Spring MVC - security(上)

这部分的内容基本上和 [spring] rest api security 是重合的,主要就是添加 验证(authentication)和授权(authorization)这两个功能

即:

  • 用户提供的验证信息是否正确
  • 用户是否有权限访问当前资源

整体流程大致如下:

auth flowchart

项目设置

这里依旧使用 https://start.spring.io/ 去进行配置,需要的 POM 如下:

在这里插入图片描述

这里和 [spring] rest api security 有区别的地方在于添加了一个 thymeleaf 的依赖:

在这里插入图片描述

这个也是 https://start.spring.io/ 自动添加的

基础 view

spring boot 会自动实现一个登录的页面,这里主要是新建一个 DemoController 去进行路径的 mapping,即提供一个登录完成后重定向的页面

代码实现如下:

  • java controller

    @Controller
    public class DemoController {@GetMapping("/")public String showHome() {return "home";}
    }
  • HTML 模板

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8" /><title>Home</title></head><body><h2>Home Page</h2><hr />Dummy Home Page</body>
    </html>
    

实现效果如下:

在这里插入图片描述

⚠️:这个登录页面是 spring boot 实现的

在没有任何配置的情况下,spring boot 默认提供的用户名是 admin,密码则是自动生成的一串哈希值,会在终端显现:

在这里插入图片描述

用户信息验证成功后,就会重定向到 mapping 好的首页:

在这里插入图片描述

基本安全配置

这里就是在代码里手动写死用户名、密码和权限,这个目前是为了简单实现,后面会添加数据库部分的实现

java 代码如下:

@Configuration
public class DemoSecurityConfig {@Beanpublic InMemoryUserDetailsManager userDetailsManager() {UserDetails john = User.builder().username("john").password("{noop}test123").roles("EMPLOYEE").build();UserDetails mary = User.builder().username("mary").password("{noop}test123").roles("EMPLOYEE", "MANAGER").build();UserDetails susan = User.builder().username("susan").password("{noop}test123").roles("EMPLOYEE", "MANAGER", "ADMIN").build();return new InMemoryUserDetailsManager(john, mary, susan);}
}

配置完并自动重启项目后,内存中的用户信息就具有更高的权重值,spring boot 也不会自动生成哈希值去和 admin 进行适配

自定义登录页面

这里有 3 个步骤要去做:

  1. 重新写 spring 的安全配置,使用自己的 HTML 模板取代 spring boot 内置的 HTML 模板

    具体实现如下:

    @Configuration
    public class DemoSecurityConfig {// 省略 inMemoryUserDetails 的实现@Beanpublic SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {httpSecurity.authorizeHttpRequests(configurer ->configurer.anyRequest().authenticated()).formLogin(form ->form.loginPage("/showMyLoginPage").loginProcessingUrl("/authenticateUser")    // no controller request mapping for this.permitAll());return httpSecurity.build();}
    }
    

    其中:

    • SecurityFilterChain 主要是用来处理 HTTP 请求,对其进行安全处理

    • HttpSecurity 则是具体对 HTTP 请求进行安全处理的配置

    • authorizeHttpRequests 代表所有的 HTTP 请求都必须要进行安全处理,即登录验证

      简单的说,访客是没有权限访问当前应用

    • formLogin 是表单登录验证

      这里主要进行 3 个处理

      1. loginPage 是登录页面的路径

      2. loginProcessingUrl 是提交登录信息的路径

        参考之前在 [spring] Spring MVC & Thymeleaf(上) 中实现的@RequestMapping("/processForm")"

        不过这个路径会被 spring 在内部处理,所以不需要手动实现一个 controller 去完成功能

    1. permitAll() 代表所有人都可以访问,包括访客

      这是一定要加的,不然登录页面本身就会需要用户验证

  2. 在 controller 层进行配置,对登录页面进行重定向

    
    @Controller
    public class LoginController {@GetMapping("/showLoginPage")public String showLoginPage() {return "plain-login";}
    }

    这是另一个 controller,专门负责登录页面的重定向,与 DemoController 不一样

    可以理解成这个 controller 负责的是所有不需要验证信息的访问,包括后面会处理的报错页面

  3. 实现 HTML 模板引擎

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8" /><title>Custom Login Page</title></head><body><h3>My Custom Login Page</h3><form method="post" action="#" th:action="@{/authenticateUser}"><p><label for="username">Username:</label><input type="text" name="username" id="username" /></p><p><label for="password">Password:</label><input type="password" name="password" id="password" /></p><input type="submit" value="Login" /></form><script src="http://localhost:35729/livereload.js"></script></body>
    </html>
    

    其中 th:action="@{/authenticateUser}" 这个语法是将 authenticateUser 绑定到当前路径下。如当前路径为 http://localhost:8080/sighup,那么这个表单提交的 URL 为 http://localhost:8080/sighup/authenticateUser。这样实现的优点在于不用写死路径

添加错误信息

目前登录页面是没有报错信息的,想要解决这个方法也很简单,可以使用 error 这个状态:

在这里插入图片描述

⚠️:这是 spring boot 实现的自动重定向,想要修改的话也可以在 formLogin 进行自定义配置

这里实现一个比较通用的报错信息:

<div th:if="${param.error}"><i>You have entered invalid username/password.</i>
</div>

最终显示效果:

在这里插入图片描述

添加登出功能

这里 logout 也使用 spring boot 的默认方法,config 修改如下:

    @Beanpublic SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {httpSecurity.authorizeHttpRequests(configurer ->configurer.anyRequest().authenticated()).formLogin(form ->form.loginPage("/showLoginPage").loginProcessingUrl("/authenticateUser")    // no controller request mapping for this.permitAll()).logout(LogoutConfigurer::permitAll);return httpSecurity.build();}

HTML 模板更新如下:

<form action="#" method="post" th:action="@{/logout}"><input type="submit" value="Logout " />
</form>

实现效果:

在这里插入图片描述

这里 CSS 修改了一下,不过主要核心内容还是一样的

用户 & 权限

下面会实现根据用户权限限制用户访问的功能

显示用户名和权限

spring security 会将当前用户的验证信息传导 view 层,获取方法如下:

<!DOCTYPE html>
<htmllang="en"xmlns:th="http://www.thymeleaf.org"xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
><body><p>User: <span sec:authentication="principal.username"></span> <br /><br />Role(s): <span sec:authentication="principal.authorities"></span></p><script src="http://localhost:35729/livereload.js"></script></body>
</html>

渲染结果:

在这里插入图片描述


在这里插入图片描述

根据权限限制访问

这里可以通过两步实现:

  1. 添加对应的 controller & view 层实现重定向功能

    ⚠️:这里用户已经登录成功了,所以对应的功能在 DemoController 中实现:

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

    随后就是更新 Home 页面中,添加重定向的功能:

    <p><a th:href="@{/leaders}">Leadership Meeting</a>(Only for Manager peeps)
    </p>
    

    以及实现对应的 Leaders 页面:

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8" /><title>Leaders</title></head><body><h2>Leaders</h2><hr /><p>Page only available for Manager role</p><a th:href="@{/}">Back to Home Page</a><script src="http://localhost:35729/livereload.js"></script></body>
    </html>
    
  2. 在 security config 中限制用户的访问权限

    实现如下:

        @Beanpublic SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {httpSecurity.authorizeHttpRequests(configurer ->configurer.requestMatchers("/").hasRole("EMPLOYEE").requestMatchers("/leaders/**").hasRole("MANAGERS").requestMatchers("/systems/**").hasRole("ADMIN").anyRequest().authenticated()).formLogin(form ->form.loginPage("/showLoginPage").loginProcessingUrl("/authenticateUser")    // no controller request mapping for this.permitAll()).logout(LogoutConfigurer::permitAll);return httpSecurity.build();}
    

    完成这一步后,只有有对应权限的用户可以访问对应的页面

    John 只有 EMPLOYEE 的权限,因此只能访问首页,而 mary 和 susan 有 MANAGERS 的权限,所以它们可以访问 leaders 下的资源

实现效果如下:

在这里插入图片描述

⚠️:同样的变化也可以加到 admin 权限和 system 页面上,这里就不重复了

拒绝访问页面

目前因为 spring 没有对相应的报错页面进行配置,因此当权限不够(403)时,会显示 whitelabel 页面。鉴于大多数用户并不能够了解 HTTP 状态码,显然这不是一个用户友好型的实现

重定向一个对应的报错页面的实现就能够很好的提升用户体验

这里的实现和自定义登录/登出页面相似,主要是在 exceptionHandling 添加对应的报错页面:

    @Beanpublic SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {httpSecurity.authorizeHttpRequests(configurer ->configurer.requestMatchers("/").hasRole("EMPLOYEE").requestMatchers("/leaders/**").hasRole("MANAGER").requestMatchers("/systems/**").hasRole("ADMIN").anyRequest().authenticated()).formLogin(form ->form.loginPage("/showLoginPage").loginProcessingUrl("/authenticateUser")    // no controller request mapping for this.permitAll()).logout(LogoutConfigurer::permitAll).exceptionHandling(configurer ->configurer.accessDeniedPage("/access-denied"));return httpSecurity.build();}

controller 的实现如下:

    @GetMapping("/access-denied")public String showAccessDenied() {return "access-denied";}

⚠️:这里的实现我也放在了 LoginController 下面……其实感觉这个 controller 应该重命名为 auth controller 比较好

HTML 模板实现如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8" /><title>Access Denied</title></head><body><h2>Access Denied - You are not ahtorized to access this resource.</h2><a th:href="@{/}">Back to Home Page</a><script src="http://localhost:35729/livereload.js"></script></body>
</html>

最终效果:

在这里插入图片描述

根据权限显示用户信息

目前的首页显示时完全一致的,不过对于 EMPLOYEE 权限的用户显示无法访问的页面,意义不是很大

这时候可以使用 spring security 提供的 sec:authorize="hasRole('ROLE')" 语法:

<p sec:authorize="hasRole('MANAGER')"><a th:href="@{/leaders}">Leadership Meeting</a>(Only for Manager peeps)
</p><p sec:authorize="hasRole('ADMIN')"><a th:href="@{/systems}">System Meeting</a>(Only for ADMIN peeps)
</p>

效果如下:

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

目前的项目结构如下:

在这里插入图片描述

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

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

相关文章

HTTPS 发送请求出现TLS握手失败

最近在工作中&#xff0c;调外部接口&#xff0c;发现在clientHello步骤报错&#xff0c;服务端没有返回serverHello。 从网上找了写方法&#xff0c;都没有解决&#xff1b; 在idea的vm options加上参数&#xff1a; -Djavax.net.debugSSL,handshake 把SSL和handshake的日…

构建基于Spring Cloud的微服务监控系统

构建基于Spring Cloud的微服务监控系统 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 随着微服务架构的流行&#xff0c;应用程序变得更加复杂和分布式&…

python自动化办公之cryptography加密解密

目录 用到的库 实现效果 代码部分 1、加密2024.txt文件 2、解密2024.txt文件 用到的库 cryptography 实现效果 加密文件和解密文件 代码部分 1、加密2024.txt文件 # 加密 from cryptography.fernet import Fernet # 生成加密密钥 keyFernet.generate_key() cipher_s…

go语言中使用WaitGroup和channel实现处理多线程问题

WaitGroup 背景 如果将一个任务分为任意个小任务&#xff0c;并且不关心小任务的执行顺序&#xff0c;并且希望等待全部的小任务执行完成后再去操作后面的逻辑&#xff0c;那我推荐你用sync.WaitGRoup 使用方法 比如&#xff0c;有一个任务需要执行 3 个子任务&#xff0c;…

Raw Socket(一)实现TCP三次握手

实验环境&#xff1a; Windows物理机&#xff1a;192.168.1.4 WSL Ubuntu 20.04.6 LTS&#xff1a;172.19.32.196 Windows下的一个http服务器&#xff1a;HFS&#xff0c;大概长这个样子&#xff1a; 客户端就是Ubuntu&#xff0c;服务端就是这个…

收银系统源码-线上商城预售功能

1.功能描述 预售&#xff1a;智慧新零售收银系统&#xff0c;线上商城营销插件之一&#xff0c;商品出售时可设置以支付定金或全款的方式提前预售&#xff0c;门店按订单量备货&#xff0c;降低压货成本&#xff1b; 2.适用场景 易损商品提前下单备货&#xff0c;如水果生鲜…

【算法笔记自学】第 5 章 入门篇(3)——数学问题

5.1简单数学 #include <cstdio> #include <algorithm> using namespace std; bool cmp(int a,int b){return a>b; } void to_array(int n,int num[]){for(int i0;i<4;i){num[i]n%10;n /10;} } int to_number(int num[]){int sum0;for(int i0;i<4;i){sumsu…

C++ Lambda表达式第二篇, Lambda表达式

C Lambda表达式 Lambda 捕获含有模板参数的Lambda表达式无模板参数的Lambda表达式 Lambda 捕获 captures是零个或多个捕获的逗号分隔列表&#xff0c;可以选择以capture-default开头。捕获列表定义可从 lambda 函数体内访问的外部变量。唯一的捕获默认值是 &&#xff0c;…

Kylin系列(二)架构解析:深入理解 Kylin 的架构设计

目录 1. 引言 2. Kylin 的基本概念 2.1 预计算 2.2 多维数据集&#xff08;Cube&#xff09; 2.3 维度和度量 3. Kylin 的架构设计 3.1 数据源 3.2 数据建模 3.2.1 星型模型 3.2.2 雪花模型 3.3 多维数据集构建 3.3.1 数据导入 3.3.2 维度和度量计算 3.3.3 存储优…

AI微电影制作教程:轻松打造高清小人国画面

AI微电影作为一种新兴的视频内容形式&#xff0c;以其独特的视觉效果和制作技术在各大视频平台上取得了显著的流量表现。 2. AI微电影的特点 2.1 高清画质与流畅动作&#xff1a;AI微电影以其高分辨率和流畅的动作给观众带来优质的视觉体验。 2.2 微缩画面效果&#xff1a;独…

大数据面试题之Presto[Trino](6)

如何诊断Presto查询慢的问题&#xff1f; 诊断Presto查询慢的问题通常需要一个系统化的方法&#xff0c;结合监控、日志分析、查询优化策略和系统配置调整等多个方面。以下是一些具体的步骤和建议&#xff1a;1、查看Presto Dashboard&#xff1a; 登录Presto的Web UI&#xf…

WebKit 入门案例教程

WebKit 的基本概念 1.什么是 WebKit&#xff1f;&#xff1a;WebKit 是一个开源的浏览器引擎&#xff0c;用于渲染 HTML、CSS 和 JavaScript 等内容。 2.WebKit 的组件&#xff1a;WebKit 的组件包括 HTML 解析器、CSS 解析器、JavaScript 引擎、布局引擎等。 3.WebKit 的应用…

用 adb 来模拟手机插上电源和拔掉电源的情形

实用的 ADB 命令 要模拟手机从 USB 充电器上拔掉的情形&#xff0c;你可以使用&#xff1a; adb shell dumpsys battery set usb 0或者&#xff0c;如果你使用的是 Android 6.0 或更高版本的设备&#xff0c;你可以使用&#xff1a; adb shell dumpsys battery unplug要重新…

使用Docker、Docker-compose部署单机版达梦数据库(DM8)

安装前准备 Linux Centos7安装&#xff1a;https://blog.csdn.net/andyLyysh/article/details/127248551?spm1001.2014.3001.5502 Docker、Docker-compose安装&#xff1a;https://blog.csdn.net/andyLyysh/article/details/126738190?spm1001.2014.3001.5502 下载DM8镜像 …

三种 FRR 技术演进 LFA、rLFA、Ti-LFA

FRR&#xff1a;Fast ReRoute 快速重路由&#xff0c;是为最大程度地减少流量损失&#xff0c;路由器预先安装一条备份路径&#xff0c;当故障发生的时候&#xff0c;由邻近故障点的路由器&#xff08;PLR&#xff1a;Point of Local Repair&#xff0c;本地修复节点&#xff0…

在Java Web项目中遇到过哪些技术难题以及如何解决的

在Java Web项目中&#xff0c;开发者可能会遇到多种技术难题。这些难题可能涉及框架使用、性能优化、安全性、数据库交互、前后端交互等多个方面。以下是一些常见的技术难题及其可能的解决方案&#xff1a; 1. 框架使用问题 难题&#xff1a; Spring Boot、Spring MVC等框架…

自动控制:前馈控制

自动控制&#xff1a;前馈控制 前馈控制是一种在控制系统中通过预先计算和调整输入来应对已知扰动或变化的方法。相比于反馈控制&#xff0c;前馈控制能够更快速地响应系统的变化&#xff0c;因为它不依赖于系统输出的反馈信号。前馈控制的应用在工业过程中尤为广泛&#xff0…

银河麒麟(V10SP1)-arm版交叉编译-qt-5.12.12源码

前言 确实是编译出来了qtbase库和qtwebengine库&#xff0c;如果按照文章没有操作出来有两种情况 (1) 读者阅读不仔细 (2) 我后期记录整理时写错了 不完美之处和遗留问题 读者阅读前须知 1. 最后发现没有生成libqxcb库文件,如果在国产化系统上执行qt程序时依赖的是自己编译…

element-ui输入框如何实现回显的多选样式?

废话不多说直接上效果&#x1f9d0; 效果图 <template><div><el-form:model"params"ref"queryForm"size"small":inline"true"label-width"68px"><el-form-item label"标签" prop"tag&q…

基于java+springboot+vue实现的仓库管理系统(文末源码+lw+ppt)23-499

第1章 绪论 伴随着信息社会的飞速发展&#xff0c;仓库管理所面临的问题也一个接一个的出现&#xff0c;所以现在最该解决的问题就是信息的实时查询和访问需求的问题&#xff0c;以及如何利用快捷便利的方式让访问者在广大信息系统中进行查询、分享、储存和管理。这对我们的现…