spring boot(学习笔记第十二课)

news2024/12/26 0:18:16

spring boot(学习笔记第十二课)

  • Spring Security内存认证,自定义认证表单

学习内容:

  1. Spring Security内存认证
  2. 自定义认证表单

1. Spring Security内存认证

  1. 首先开始最简单的模式,内存认证。
    • 加入spring security的依赖。
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-security</artifactId>
      </dependency>
      
    • 加入controller进行测试。
       @GetMapping("/security_hello")
       @ResponseBody
          public String hello(){
              return "hello,security";
          }
      
    • 启动应用程序。
      默认的用户名是user,密码会在log中出现。
      Using generated security password: 9b7cd16e-af9e-4804-a6a2-9303df66ace8
      
    • 访问controller,可以看到这里在这里插入图片描述 * 输入上面的密码,进行login。
      在这里插入图片描述
  2. 接着开始在内存中定义认证的用户和密码。
    • 定义内存用户,设定安全设置@configuration
      @Configuration
      public class SecurityConfig {
          @Bean
          PasswordEncoder passwordEncoder() {
              return NoOpPasswordEncoder.getInstance();
          }
      
          @Bean
          UserDetailsService userDetailsService() {
              InMemoryUserDetailsManager users =
                      new InMemoryUserDetailsManager();
              users.createUser(User.withUsername("finlay_admin")
                      .password("123456")
                      .roles("ADMIN")
                      .build());
              users.createUser(User.withUsername("finlay_dba")
                      .password("123456")
                      .roles("DBA")
                      .build());
              users.createUser(User.withUsername("finlay_super")
                      .password("123456")
                      .roles("ADMIN", "DBA")
                      .build());
              return users;
          }
      
          @Bean
          SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
              http.authorizeHttpRequests(auth -> auth.requestMatchers
                                      ("/**")//匹配所有/** url
                              .hasRole("ADMIN")//定义/**访问所需要ADMIN的role
                              .anyRequest()//设定任何访问都需要认证
                              .authenticated()//设定任何访问都需要认证
                      )
                      .csrf(csrf -> csrf.disable())//csrf跨域访问无效 Cross-Site Request Forgery
                      .sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(true));
              return http.build();
          }
      
    • finlay_dba这个user只设定了DBArole,login是无效的
      在这里插入图片描述
    • finlay_super这个user只设定了DBArole,login是无效的
  3. 进一步 测试详细的权限设定。
    • 定义controller
       @GetMapping("/admin/hello")
          @ResponseBody
          public String helloAdmin() {
              return "hello,admin";
          }
      
          @GetMapping("/user/hello")
          @ResponseBody
          public String helloUser() {
              return "hello,user";
          }
      
          @GetMapping("/db/hello")
          @ResponseBody
          public String helloDB() {
              return "hello,DBA";
          }
      
          @GetMapping("/hello")
          @ResponseBody
          public String hello() {
              return "hello";
          }
      
    • 细化各种url的访问权限。
      @Configuration
      public class SecurityConfig {
          @Bean
          PasswordEncoder passwordEncoder() {
              return NoOpPasswordEncoder.getInstance();
          }
      
          @Bean
          UserDetailsService userDetailsService() {
              InMemoryUserDetailsManager users =
                      new InMemoryUserDetailsManager();
              users.createUser(User.withUsername("finlay_user")
                      .password("123456")
                      .roles("USER")
                      .build());
              users.createUser(User.withUsername("finlay_admin")
                      .password("123456")
                      .roles("ADMIN")
                      .build());
              users.createUser(User.withUsername("finlay_dba")
                      .password("123456")
                      .roles("DBA")
                      .build());
              users.createUser(User.withUsername("finlay_super")
                      .password("123456")
                      .roles("ADMIN", "DBA")
                      .build());
              return users;
          }
      
          @Bean
          SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
              httpSecurity.authorizeHttpRequests(
                              auth ->
                                      auth.requestMatchers("/admin/**")//匹配所有/** url
                                              .hasRole("ADMIN")//只能对于admin的role,才能访问
                                              .requestMatchers("/user/**")//匹配/user/**
                                              .hasRole("USER")//只有对于user的role,才能访问
                                              .requestMatchers("/db/**")//配置/db/**
                                              .hasRole("DBA")//只有对于dba的role,才能访问
                                              .anyRequest()
                                              .authenticated()//设定任何访问都需要认证
                      )
                      .formLogin(form -> form.loginProcessingUrl("/login")//这里对于前后端分离,提供的非页面访问url
                              .usernameParameter("username")//页面上form的用户名
                              .passwordParameter("password"))//页面上form的密码
                      .csrf(csrf -> csrf.disable())//csrf跨域访问无效
                      .sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(true));
              return httpSecurity.build();
          }
      }
      
    • 尝试访问/db/hello
      在这里插入图片描述
    • 清除chrome浏览器的session数据。
      因为没有定义logout功能,所以每次login成功之后,都不能消除login情报,这时候可以在chrome浏览器直接使用快捷键ctrl-shift-del之后进行session情报的删除。这样能够进行测试。在这里插入图片描述

2. 自定义认证表单

通常的情况是不用spring security默认提供的页面,下面进行自定义认证页面。

  1. 继续在SecurityConfigcontroller以及html中进行配置`
    • 配置自定义的认证url
       @Bean
          SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
              httpSecurity.authorizeHttpRequests(auth ->
                              auth.requestMatchers("/login*")
                                      .permitAll()
                                      .requestMatchers("/admin/**")//匹配所有/** url
                                      .hasRole("ADMIN")//只能对于admin的role,才能访问
                                      .requestMatchers("/user/**")//匹配/user/**
                                      .hasRole("USER")//只有对于user的role,才能访问
                                      .requestMatchers("/db/**")//配置/db/**
                                      .hasRole("DBA")//只有对于dba的role,才能访问
                                      .anyRequest()
                                      .authenticated()//设定任何访问都需要认证
                      )
                      .formLogin(form -> form.loginPage("/loginPage")
                              .loginProcessingUrl("/doLogin")//这里对于前后端分离,提供的非页面访问url
                              .usernameParameter("uname")//页面上form的用户名
                              .passwordParameter("passwd")
                              .successHandler(new SuccessHandler())//认证成功的处理
                              .failureHandler(new FailureHandler())//认证失败的处理
                              .defaultSuccessUrl("/index")//默认的认证之后的页面
                              .failureForwardUrl("/loginPasswordError"))//默认的密码失败之后的页面
                      .exceptionHandling(exceptionHandling ->
                              exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler()))
                      .csrf(csrf -> csrf.disable())//csrf跨域访问无效
                      .sessionManagement(session -> session.maximumSessions(1).maxSessionsPreventsLogin(true));
              return httpSecurity.build();
          }
      
      • 对于认证画面的url,进行permitAll开放,因为对于认证画面,不需要进行认证。
        auth.requestMatchers("/login*")
        .permitAll()
        
      • 定义login的认证画面url,之后会定义controllerview 注意,仅限于前后端一体程序
        .formLogin(form -> form.loginPage("/loginPage")
        
      • 定于处理认证请求的url 注意前后端一体和前后端分离程序都会使用用这个url,springboot不对这个url定义controller
         .loginProcessingUrl("/doLogin")//这里对于前后端分离,提供的非页面访问url
        
      • 对自定义页面的input进行设定,这里之后的html会使用。
        .usernameParameter("uname")//页面上form的用户名
        .passwordParameter("passwd")
        
      • 对于前后端的分离应用,直接访问doLogin,通过这里给前端返回结果对这两个类详细说明。
         .successHandler(new SuccessHandler())//认证成功的处理
         .failureHandler(new FailureHandler())//认证失败的处理
        
      • 如果直接访问loginPage,那么认证成功后默认的url就是这里
        注意,和successForwardUrl的区别是,successForwardUrlpost请求,这里是get请求
        .defaultSuccessUrl("/index")//默认的认证之后的页面
        
      • 配置密码失败之后的url
        .failureForwardUrl("/loginPasswordError"))//默认的密码失败之后的页面
        
      • 配置没有权限时候的错误页面的url,之后对CustomizeAccessDeniedHandler类进行说明。
        exceptionHandling(exceptionHandling ->
          exceptionHandling.accessDeniedHandler(new CustomizeAccessDeniedHandler()))
        
      • success handler类进行定义,主要在前后端的程序中使用。
         //success handler
            private static class SuccessHandler implements AuthenticationSuccessHandler {
                @Override
                public void onAuthenticationSuccess(
                        HttpServletRequest httpServletRequest,
                        HttpServletResponse httpServletResponse,
                        Authentication authentication
                ) throws IOException {
                    Object principal = authentication.getPrincipal();
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter printWriter = httpServletResponse.getWriter();
                    httpServletResponse.setStatus(200);
                    Map<String, Object> map = new HashMap<>();
                    map.put("status", 200);
                    map.put("msg", principal);
                    ObjectMapper om = new ObjectMapper();
                    printWriter.write(om.writeValueAsString(map));
                    printWriter.flush();
                    printWriter.close();
                }
        
      • failure handler类进行定义,主要在前后端的程序中使用。
         //failure handler
            private static class FailureHandler implements AuthenticationFailureHandler {
                @Override
                public void onAuthenticationFailure(
                        HttpServletRequest httpServletRequest,
                        HttpServletResponse httpServletResponse,
                        AuthenticationException authenticationException
                ) throws IOException {
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter printWriter = httpServletResponse.getWriter();
                    httpServletResponse.setStatus(401);
                    Map<String, Object> map = new HashMap<>();
                    map.put("status", 401);
                    if (authenticationException instanceof LockedException) {
                        map.put("msg", "账户被锁定,登陆失败");
                    } else if (authenticationException instanceof BadCredentialsException) {
                        map.put("msg", "账户输入错误,登陆失败");
                    } else {
                        map.put("msg", "登陆失败");
                    }
                    ObjectMapper om = new ObjectMapper();
                    printWriter.write(om.writeValueAsString(map));
                    printWriter.flush();
                    printWriter.close();
                }
        
      • CustomizeAccessDeniedHandler类进行定义,对没有权限等情况进行定义。比如,需要的roleADMIN,但是认证结束后的role确是DBA
        private static class CustomizeAccessDeniedHandler implements AccessDeniedHandler {
                @Override
                public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
                    response.sendRedirect("/loginNoPermissionError");
                }
            }
        
    • controller层做出一个LoginController 注意,为了定义permitAll方便,统一采用login`开头
      @Controller
      public class LoginController {
          @GetMapping("/loginPage")
          public String loginPage() {
              return "login";
          }
      
          @GetMapping("/loginNoPermissionError")
          public String loginNoPermission() {
              return "no_permission_error";
          }
      
          @GetMapping("/loginPasswordError")
          public String loginError(Model model) {
              model.addAttribute("message", "认证失败");
              return "password_error";
          }
          @PostMapping("/loginPasswordError")
          public String loginErrorPost(Model model) {
              model.addAttribute("message", "认证失败");
              return "password_error";
          }
      }
      
    • 定义view层的各个html 注意,前后端分离程序
      • login的认证画面view
        <!DOCTYPE HTML>
        <html xmlns:th="http://www.thymeleaf.org/" lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Spring Security 用户自定义认证画面</title>
        </head>
        <body>
        <h1>自定义用户登陆</h1>
        <form th:action="@{/doLogin}" method="post">
            用户名:<input type="text" name="uname"><br>
            密码:<input type="text" name="passwd"><br>
            <input type="submit" value="登陆">
        </form>
        </body>
        </html>
        
      • 定义密码错误的认证错误画面view
        <!DOCTYPE HTML>
        <html xmlns:th="http://www.thymeleaf.org/" lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Spring Security 用户自定义-密码输入错误</title>
        </head>
        <body>
        <h1>自定义用户登陆错误-用户密码输入错误"</h1>
        </form>
        </body>
        </html>
        
      • 定义没有权限的认证错误画面view,比如需要ADMINrole,但是用户只有DBArole
        <!DOCTYPE HTML>
        <html xmlns:th="http://www.thymeleaf.org/" lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Spring Security 用户自定义-权限不足</title>
        </head>
        <body>
        <h1>"用户自定义画面,权限不足"</h1>
        </form>
        </body>
        </html>
        
  2. 验证结果
    • DBA用户访问http://localhost:8080/db/hello在这里插入图片描述
    • 输入错误密码
      在这里插入图片描述
    • USERrole用户登录,但是访问http://localhost:8080/db/hello,需要DBArole
      在这里插入图片描述

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

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

相关文章

edge浏览器详细解析

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 Microsoft Edge ​​​​…

InvalidVersionSpecError: Invalid version spec: =2.7解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

C++ | Leetcode C++题解之第22题完全二叉树的节点个数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countNodes(TreeNode* root) {if (root nullptr) {return 0;}int level 0;TreeNode* node root;while (node->left ! nullptr) {level;node node->left;}int low 1 << level, high (1 <&…

详解Java垃圾回收(GC)机制

一、为什么需要垃圾回收 如果不进行垃圾回收&#xff0c;内存迟早都会被消耗空&#xff0c;因为我们在不断的分配内存空间而不进行回收。除非内存无限大&#xff0c;我们可以任性的分配而不回收&#xff0c;但是事实并非如此。所以&#xff0c;垃圾回收是必须的。 二、哪些内…

计算机的错误计算(二十四)

摘要 计算机的错误计算&#xff08;二十一&#xff09;就案例 展示了“两个不相等数相减&#xff0c;差为0”。本节给出新的计算过程&#xff1a;不停增加计算精度直到出现非0结果。这个过程与结果表明&#xff0c;即使是专业数学软件&#xff0c;对这个问题的处理&#xff0…

JS进阶-作用域

学习目标&#xff1a; 掌握作用域 学习内容&#xff1a; 作用域局部作用域全局作用域作用域链JS垃圾回收机制拓展-JS垃圾回收机制-算法说明闭包变量提升 作用域&#xff1a; 作用域规定了变量能够被访问的"范围"&#xff0c;离开了这个"范围"变量便不能被…

论文1:多模态人类活动识别综述

论文题目&#xff1a;A Review of Multimodal Human Activity Recognition with Special Emphasis on Classification, Applications, Challenges and Future Directions 文献偏旧-2021 1、 专业词汇&#xff1a; Human activity recognition (HAR)-人类活动识别 Wearable …

Open3D 计算点云的马氏距离

目录 一、概述 1.1原理 1.2应用 二、代码实现 三、实现效果 3.1原始点云 3.2计算后点云 一、概述 1.1原理 马氏距离&#xff08;Mahalanobis Distance&#xff09;是一种度量多维数据点与数据分布中心之间距离的方法。与欧几里得距离不同&#xff0c;马氏距离考虑了数据…

树目标、抓过程、要结果

一个好的管理理念不会因为一两个成功案例而发扬&#xff0c;一定是有无数个案例验证了它的价值所在&#xff0c;既然OKR在国外已经取得成功&#xff0c;那么国内依然如此。那么OKR这么成功&#xff0c;它到底好在哪呢&#xff1f; 一、OKR是连接企业战略和落地执行的最佳方式。…

C嘎嘎:类和对象(上)

目录 面向过程和面向对象的初步认识 类的引入 类的定义 类的访问限定符及封装 访问限定符 封装 类的作用域 类的实例化 类对象模型 如何计算类对象大小 结构体内存对齐规则 this指针 this指针的引出 this指针的特性 面向过程和面向对象的初步认识 C语言是面向过程…

CentOS 6.5配置国内在线yum源和制作openssh 9.8p1 rpm包 —— 筑梦之路

CentOS 6.5比较古老的版本了&#xff0c;而还是有一些古老的项目仍然在使用。 环境说明 1. 更换国内在线yum源 CentOS 6 在线可用yum源配置——筑梦之路_centos6可用yum源-CSDN博客 cat > CentOS-163.repo << EOF [base] nameCentOS-$releasever - Base - 163.com …

尚品汇-(十二)

&#xff08;1&#xff09;数据库表结构 根据以上的需求&#xff0c;以此将SKU关联的数据库表结构设计为如下&#xff1a; base_attr_value&#xff1a;前面学的平台属性值表 我们进行关联&#xff0c;可以从分类导向平台&#xff0c;通过平台过滤商品 &#xff08;2&#xf…

利用亚马逊云科技云原生Serverless代码托管服务开发OpenAI ChatGPT-4o应用

今天小李哥继续介绍国际上主流云计算平台亚马逊云科技AWS上的热门生成式AI应用开发架构。上次小李哥分享​了利用谷歌云serverless代码托管服务Cloud Functions构建Gemini Pro API​&#xff0c;这次我将介绍如何利用亚马逊的云原生服务Lambda调用OpenAI的最新模型ChatGPT 4o。…

【NTN 卫星通信】Starlink基于终端用户的测量以及测试概述

1 概述 收集了一些starlink的资料&#xff0c;是基于终端侧部署在野外的一些测试以及测量结果。 2 低地球轨道卫星网络概述 低地球轨道卫星网络(lsn)被认为是即将到来的6G中真正实现全球覆盖的关键基础设施。本文介绍了我们对Starlink端到端网络特征的初步测量结果和观测结果&…

基于YOLOv9的脑肿瘤区域检测

数据集 脑肿瘤区域检测&#xff0c;我们直接采用kaggle公开数据集&#xff0c;Br35H 数据中已对医学图像中脑肿瘤位置进行标注 数据集我已经按照YOLO格式配置好&#xff0c;数据内容如下 数据集中共包含700张图像&#xff0c;其中训练集500张&#xff0c;验证集200张 模型训…

DHCP与TCP的简单解析

目录 一、DHCP 1.1 DHCP概述 1.2 DHCP的优势 1.3 DHCP的模式与分配方式***** 1.3.1 DHCP的模式&#xff1a;C/S模式&#xff08;客户机与服务器模式&#xff09; 1.3.2 DHCP的分配方式 1.4 DHCP的租约过程及原理 1.4.1 DHCP的工作原理***** 1.4.2 更新租约原理***** …

D - Go Stone Puzzle(abc361)

分析&#xff1a;因为n很小&#xff0c;可以逐一搜索&#xff0c;用一个队列将每种情况列出来&#xff0c;用bfs寻找从s到t的最短路径 #include <bits/stdc.h> using namespace std; int n; string s, t; map<string, int> dis; void bfs() { dis[s] 0; …

加密与安全_常见的分组密码 ECB、CBC、CFB、OFB模式介绍

文章目录 Pre概述why分组密码和流密码的基本概念什么是模式分组密码的常见模式1. ECB 模式&#xff08;电子密码本模式&#xff09;2. CBC 模式&#xff08;密文分组链接模式&#xff09;3. CFB 模式&#xff08;密文反馈模式&#xff09;4. OFB 模式&#xff08;输出反馈模式&…

MySQL安装时initializing database失败

问题页面&#xff1a; 解决方法&#xff1a; 1.勾选红框中的选项&#xff1a; 2.将下图红框中全部改为英文&#xff1a; 然后一路next就可以了。

VRay渲染有什么技巧?渲染100邀请码1a12

渲染是视觉行业非常重要的一环&#xff0c;没有渲染就没有效果图&#xff0c;常用的渲染器有Vray&#xff0c;而Vray渲染有很多技巧&#xff0c;可以让渲染更快更省&#xff0c;下面我们总结下。 1、删除无用对象 检查场景&#xff0c;看是否有一些不需要渲染的物体和灯光&am…