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

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
      在这里插入图片描述

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

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

相关文章

【TB作品】51单片机 Proteus仿真 MAX7219点阵驱动数码管驱动

1、8乘8点阵模块&#xff08;爱心&#xff09; 数码管测试程序与仿真 实验报告: MAX7219 数码管驱动测试 一、实验目的 通过对 MAX7219 芯片的编程与控制&#xff0c;了解如何使用单片机驱动数码管显示数字&#xff0c;并掌握 SPI 通信协议的基本应用。 二、实验器材 51…

触发器编程-创建(CREATE TRIGGER)、删除(DROP TRIGGER)

一、定义 1、触发器&#xff08;Trigger&#xff09;是用户对某一表中的数据做插入、更新和删除操作时被处罚执行的一段程序&#xff0c;通常我们使用触发器来检查用户对表的操作是否合乎整个应用系统的需求&#xff0c;是否合乎商业规则以维持表内数据的完整性和正确性 2、一…

SPL-404:如何彻底改变Solana上的NFT与DeFi

在不断发展的数字资产领域中&#xff0c;非同质化Token&#xff08;NFT&#xff09;已成为一股革命性力量&#xff0c;彻底改变了我们对数字所有权的看法和互动方式。从艺术和收藏品到游戏和虚拟房地产&#xff0c;NFT吸引了创作者、投资者和爱好者的想象力。 本指南将带您进入…

力扣-双指针1

何为双指针 双指针指向同一数组&#xff0c;然后配合着进行搜索等活动。 滑动窗口的时候很好使用。 167.两数之和Ⅱ-输入有序数组 167. 两数之和 II - 输入有序数组 题目 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从…

[Flink]三、Flink1.13

11. Table API 和 SQL 如图 11-1 所示&#xff0c;在 Flink 提供的多层级 API 中&#xff0c;核心是 DataStream API &#xff0c;这是我们开发流 处理应用的基本途径&#xff1b;底层则是所谓的处理函数&#xff08; process function &#xff09;&#xff0c;可以访…

Android 简单快速实现 下弧形刻度尺(滑动事件)

效果图&#xff1a; 直接上代码&#xff1a; package com.my.view;import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Pai…

iptables实现端口转发ssh

iptables实现端口转发 实现使用防火墙9898端口访问内网front主机的22端口&#xff08;ssh连接&#xff09; 1. 防火墙配置(lb01) # 配置iptables # 这条命令的作用是将所有目的地为192.168.100.155且目标端口为19898的TCP数据包的目标IP地址改为10.0.0.148&#xff0c;并将目标…

基于Java+SpringMvc+Vue技术的在线学习交流平台的设计与实现---60页论文参考

博主介绍&#xff1a;硕士研究生&#xff0c;专注于Java技术领域开发与管理&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架构思想、较扎实的技术功底和资深的项目管理经…

【PB案例学习笔记】-29制作一个调用帮助文档的小功能

写在前面 这是PB案例学习笔记系列文章的第29篇&#xff0c;该系列文章适合具有一定PB基础的读者。 通过一个个由浅入深的编程实战案例学习&#xff0c;提高编程技巧&#xff0c;以保证小伙伴们能应付公司的各种开发需求。 文章中设计到的源码&#xff0c;小凡都上传到了gite…

【Spring Boot】关系映射开发(三):多对多映射

《JPA 从入门到精通》系列包含以下文章&#xff1a; Java 持久层 API&#xff1a;JPA认识 JPA 的接口JPA 的查询方式基于 JPA 开发的文章管理系统&#xff08;CRUD&#xff09;关系映射开发&#xff08;一&#xff09;&#xff1a;一对一映射关系映射开发&#xff08;二&#…

Java_网络编程

网络通信的关键三要素 IP、端口号、协议 IP地址 IP地址&#xff08;Internet Protocol&#xff09;&#xff1a;全程“互联网协议地址”&#xff0c;是分配给上网设备的唯一标志。 IP地址有两种形式&#xff1a;IPv4、IPv6 InetAddress 代表IP地址 InetAddress 的常用方法…

【算法训练记录——Day42】

Day42——动态规划Ⅳ 1.leetcode_1049最后一块石头的重量II2.leetcode_494目标和3.leetcode_474一和零 1.leetcode_1049最后一块石头的重量II 思路&#xff1a;石头只能用一次。。。怎么才能让碰撞后重量最小呢&#xff0c;还要转换成动态规划&#xff0c;难以理解。。 看题解&…

J024_打印电影的全部信息

一、需求描述 展示多部电影的信息。 电影信息包括&#xff1a;电影名称、电影得分、电影票价格。 二、代码实现 2.1 Movie类 package com.itheima.collection;public class Movie {//电影名称private String name;//电影得分private int score;//电影票价格private double…

【Excel】输入内容自动添加边框线

1. 选中表格区域 → 新建条件规则 2. 设置公式 3. 设置格式 测试生效

[吃瓜教程]南瓜书第6章支持向量机

0.补充知识 0.1 超平面 定义&#xff1a; 超平面是指在&#x1d45b;维空间中&#xff0c;维度为 &#x1d45b;−1的子空间。它是分割空间的一个平面。 性质&#xff1a; n维空间的超平面 ( w T x b 0 , 其中 w , x ∈ R n ) (w^Tx_b0,其中w,x\in \mathbb R^n) (wTxb​0,其…

C++的set / multiset容器

一、介绍 C的set容器又被称为集合&#xff0c;所有元素在被插入后都会自动排序。 二、数据结构 set / multiset属于关联式容器&#xff0c;底层数据结构是用二叉树实现的。 其余的容器比如vector、deque和list等为序列式容器&#xff0c;因为他们底层使用线性序列结构&#xf…

Windows环境安装Redis和Redis Desktop Manager图文详解教程

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Redis概述 Redis是一个开源的高性能键值对数据库&#xff0c;以其卓越的读写速度而著称&#xff0c;广泛用于数据库、缓存和消息代理。它主要将数据存储在内存中&#xff0…

CISC和RISC指令集

文章目录 1. 指令集 2. CISC&#xff08;复杂指令集计算&#xff09; 3. RISC&#xff08;精简指令集计算&#xff09; 4. RISC的设计初衷 5. CISC和RISC流程对比 CISC&#xff08;复杂指令集计算&#xff09;的实现 RISC&#xff08;精简指令集计算&#xff09;的实现 …

【高中数学之函数】四种幂函数图线(二次、三次、开方、开立方)

【图像】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>UNASSIGNED</title><style type"text/css">.c…

【智能算法应用】灰狼算法求解二维栅格路径规划问题

目录 1.算法原理2.二维路径规划数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】灰狼算法&#xff08;GWO&#xff09;原理及实现 2.二维路径规划数学模型 栅格法模型最早由 W.E. Howden 于 1968 年提出&#xff0c;障碍物的栅格用黑色表示&#xff0c;可通…