[spring] Spring MVC - security(上)

news2024/9/21 18:54:56

[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 {
    @Bean
    public 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 的实现
    
        @Bean
        public 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 修改如下:

    @Bean
    public 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>
<html
  lang="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 中限制用户的访问权限

    实现如下:

        @Bean
        public 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 添加对应的报错页面:

    @Bean
    public 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.coloradmin.cn/o/1916231.html

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

相关文章

SpringBoot的老年慢性病药物管理系统-计算机毕业设计源码70568

目录 摘要 Abstract 第一章 绪论 1.1 选题背景及意义 1.2 国内外研究现状 1.3 研究方法 第二章 相关技术介绍 2.1 MySQL简介 2.2 Java编程语言 2.3 B/S模式 2.4 springboot框架 第三章 老年慢性病药物管理系统 系统分析 3.1 系统目标 3.2 系统可行性分析 3.2.1 技…

STM32中断学习记录

文章目录 NVICNVIC是什么NVIC寄存器NVIC 结构体NVIC 相关固件库函数 如何定义优先级中断编程外部中断 EXTIEXIT 外部中断/事件控制器EXIT的使用EXTI内部寄存器分析GPIO触发中断例程为什么中断后要清除中断标志位 SysTick的使用SysTick分析 NVIC NVIC是什么 待补充.........NVI…

ChatTTS的爆火是必然,它正在重新定义我们与机器对话的方式

当AI技术与语音合成相遇&#xff0c;开源技术众多&#xff0c;为什么 ChatTTS 能够一夜爆火&#xff1f;你有听说过能说情感真切文字的 AI 吗&#xff1f; 前言 想象一下&#xff0c;你只需输入一句话&#xff0c;AI就能念得声情并茂&#xff0c;不仅支持中英文混读&#xff0…

自注意力简介

在注意力机制中&#xff0c;每个查询都会关注所有的键值对并生成一个注意力输出。如果查询q&#xff0c;键k和值v都来自于同一组输入&#xff0c;那么这个注意力就被称为是自注意力&#xff08;self-attention&#xff09;。自注意力这部分理论&#xff0c;我觉得台大李宏毅老师…

一位互联网公司项目经理繁忙的一天

早晨&#xff1a;准备与计划 7:00 AM - 起床与准备 项目经理起床后&#xff0c;快速洗漱并享用早餐。之后花几分钟查看手机上的邮件和消息&#xff0c;确保没有紧急事务需要立即处理。 7:30 AM - 通勤时间 前往公司。在通勤途中&#xff0c;通过手机或平板电脑查看当天的会议…

硅谷甄选运营平台-vue3组件通信方式

vue3组件通信方式 vue2组件通信方式&#xff1a; props:可以实现父子组件、子父组件、甚至兄弟组件通信自定义事件:可以实现子父组件通信全局事件总线$bus:可以实现任意组件通信pubsub:发布订阅模式实现任意组件通信vuex:集中式状态管理容器&#xff0c;实现任意组件通信ref:父…

简单了解下安全测试!

一、基本概念 安全测试是在软件产品开发基本完成时&#xff0c;验证产品是否符合安全需求定义和产品质量标准的过程。它主要检查系统对非法侵入渗透的防范能力&#xff0c;旨在通过全面的脆弱性安全测试&#xff0c;发现系统未知的安全隐患并提出相关建议&#xff0c;确保系统…

星申刹车盘平衡机:精准与高效兼备

星申动双工位刹车盘动平衡机是一款具备测量和切削两个工位的高精度设备。该机器由平衡测量单元、内部搬运系统、切削校正模块及电气控制部分组成&#xff0c;专为满足自动化生产需求设计。其主要功能特点包括&#xff1a; 1. 实现全自动刹车盘平衡测试&#xff0c;精度高达30gm…

vue3 ts 报错:无法找到模块“../views/index/Home.vue”的声明文件

解决办法&#xff1a; env.d.ts 新增代码片段&#xff1a; declare module "*.vue" {import type { DefineComponent } from "vue";// eslint-disable-next-line typescript-eslint/no-explicit-any, typescript-eslint/ban-typesconst component: Define…

ExtruOnt——为工业 4.0 系统描述制造机械类型的本体

概述 论文地址 &#xff1a;https://arxiv.org/abs/2401.11848 原文地址&#xff1a;https://ai-scholar.tech/articles/ontology/ExtruOnt 在工业 4.0 应用场景中&#xff0c;以机器可解释代码提供的、语义丰富的制造机械描述可以得到有效利用。然而&#xff0c;目前显然还缺…

使用nvm安装node包后,安装vue提示“vue不是内部或外部命令,也不是可运行的程序或批处理命令”

前言 使用 npm 安装了 vue-cli 后&#xff0c;输入 "vue -V" 查询vue版本命令提示&#xff1a; “vue不是内部或外部命令,也不是可运行的程序或批处理命令”。 解决方法 第一步&#xff1a;首先&#xff0c;查看 C 盘下有没有 npm 文件夹。 目录类似于&#xff1…

六、数据可视化—Echars(爬虫及数据可视化)

六、数据可视化—Echars&#xff08;爬虫及数据可视化&#xff09; Echarts应用 Echarts Echarts官网&#xff0c;很多图表等都是我们可以 https://echarts.apache.org/zh/index.html 是百度自己做的图表&#xff0c;后来用的人越来越多&#xff0c;捐给了orange组织&#xf…

网络渗透CTF实践:获取靶机Web Developer 文件/root/flag.txt中flag

实验目的&#xff1a;通过对目标靶机的渗透过程&#xff0c;了解CTF竞赛模式&#xff0c;理解CTF涵盖的知识范围&#xff0c;如MISC、PPC、WEB等&#xff0c;通过实践&#xff0c;加强团队协作能力&#xff0c;掌握初步CTF实战能力及信息收集能力。熟悉网络扫描、探测HTTP web服…

交易员需要克服的十大心理问题

撰文&#xff1a;Koroush AK 编译&#xff1a;Chris&#xff0c;Techub News 本文来源香港Web3媒体&#xff1a;Techub News 一个交易者在交易上所犯下的最大的错误可能更多来自于心态的失衡而并非技术上的失误&#xff0c;类似的情况已经发生在了无数交易者身上。作为交易者…

如何压缩pdf文件大小,怎么压缩pdf文件大小

在数字化时代&#xff0c;pdf文件因其稳定的格式和跨平台兼容性&#xff0c;成为了工作与学习中不可或缺的一部分。然而&#xff0c;随着pdf文件内容的丰富&#xff0c;pdf文件的体积也随之增大&#xff0c;给传输和存储带来了不少挑战。本文将深入探讨如何高效压缩pdf文件大小…

C++入门 模仿mysql控制台输出表格

一、 说明 控制台输出表格&#xff0c;自适应宽度 二、 源码 #include <iostream> #include <map> #include <string> #include <vector>using namespace std;void printTable(vector<vector<string>> *pTableData) {int row pTableDa…

前端八股文 箭头函数和普通函数的区别

箭头函数是匿名函数&#xff0c;不能作为构造函数&#xff0c;不能使用new箭头函数不绑定 arguments &#xff0c;取而代之用 rest 参数...解决箭头函数不绑定 this &#xff0c;会捕获其所在的上下文的this值&#xff0c;作为自己的this值箭头函数通过 call() 或 apply() 方法…

【学术会议征稿】第四届新材料与化学工程国际学术会议(AMCE 2024)

第四届新材料与化学工程国际学术会议&#xff08;AMCE 2024&#xff09; 2024 4th International Conference on Advanced Materials and Chemical Engineering 为了促进我国新材料与化学工程领域绿色、规范、持续、健康发展,提升科技创新能力&#xff0c;推进学科交叉融合和…

苹果笔记本电脑能玩哪些游戏 苹果电脑可以玩的单机游戏推荐

苹果笔记本有着优美的外观和强大的性能。用户不仅可以使用苹果笔记本办公、剪辑&#xff0c;越来越多的用户开始关注苹果笔记本在游戏领域的表现&#xff0c;尤其是在大型游戏方面。本文将为你详细介绍苹果笔记本都能玩什么游戏&#xff0c;以及为你推荐苹果电脑可以玩的单机游…

浙江宁波G761-3005B穆格伺服阀 有货

G761-3005B穆格伺服阀是一种用于流体控制的阀门。 宁波秉圣与各国的多家进口产品维护服务提供商建立了紧密的合作关系。我们售出的产品提供1年的质保&#xff0c;并且都经过了严格的测试和认证。公司的优势品牌如下&#xff1a;德国MOOG、美国 PARKER&#xff08;派克&#xf…