六:Day05_Spring Security01

一、Spring Security引入

Spring Security 是一个功能强大且高度可定制的身份验证和访问控制(认证和授权)框架。它是保护基于 Spring 应用程序的事实标准。

2. 认证授权

  • 认证授权实现平台所有用户的身份认证与用户授权功能。

2.1 什么是用户认证
  • 认证:Authentication

验证某个用户能否访问该系统。一般要求用户提供用户名和密码,手机号验证码等,系统通过校验来完成认证过程。

2.2 什么是用户授权
  • 授权:Authorization

用户认证通过后去访问系统的资源,系统会判断用户是否拥有访问资源的权限,只允许访问有权限的系统资源,没有权限的资源将无法访问。

3. 常见认证方式

3.1 Http basic 认证

http basic auth 通过使用Restful风格开发,每次请求服务器都携带用户名和密码。这种方式使用越来越少,因为不安全。

3.2 Session 认证

会话认证就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器段创建了一个Cookie对象(保存sessionID),通过客户端带上来Cookie对象来与服务器端Session对象匹配实现用户状态管理的。

3.3 Token 认证

使用基于Token的身份验证方法,在服务端不需要存储用户的登录记录。大概流程如下:

  1. 客户端使用用户名和密码请求登录

  2. 服务端收到请求,去验证用户名与密码

  3. 验证成功后,服务器颁发一个Token,再把这个Token发送给客户端

  4. 客户端收到Token以后把它存储起来

  5. 客户端每次向服务器端请求资源的时候需要带着Token

  6. 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据。

3.4 OAuth2 认证

 例如:微信扫码认证,这是一种第三方认证的方式,这种认证方式是基于OAuth2协议实现。

OAUTH协议为用户资源的授权提供了一个安全的、开放而又简易的标准。同时,任何第三方都可以使用OAUTH认证服务,任何服务提供商都可以实现自身的OAUTH认证服务。

二、Spring Security介绍

  • 两个主要区域是“认证(authentication)”和“授权(authorization)”。这两点也是Spring Security重要核心功能。
  • Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架,它是一个专注于为 Java 应用程序提供身份验证和授权的框架。

Spring Security项目主页:Spring Security

Spring cloud Security: Spring Cloud Security

三、认证快速入门

1. 引入依赖

<!-- 引入web项目启动器 --> 
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入Spring Security启动器 --> 
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>

2. 创建控制器

@RestController
public class UserController {@RequestMapping("show")public String show(){return "Hello World!";}
}

3. 访问资源

导入spring-boot-starter-security启动器后,Spring Security已经生效,默认拦截全部请求,如果用户没有登录,跳转到内置登录页面。

4. 完成登录

5. 自定义登录用户名和密码

spring:security:user:name: rootpassword: root

四、自定义认证逻辑(重要)

1. UserDetailsService接口

当什么也没有配置的时候,账号和密码是由Spring Security定义生成的,存储在内存中。

而在实际项目中账号和密码都是从数据库中查询出来的。 所以我们需要通过自定义逻辑控制认证(登录)逻辑。

如果需要自定义逻辑时,只需要实现UserDetailsService接口即可。

接口定义如下:

  • 默认策略:浏览器发起请求,经过拦截器:

    • 没有认证(没有登录),执行UserDetailsService接口实现类InMemoryUserDetailsManager中loadUserByUsername()方法,将输入的用户名和内存中用户名完成比较,用户名比较通过后,再比较输入的密码和内存中的密码。

  • 如果用户名和密码需要从数据库查询后再完成比较,重写UserDetailsService接口中的loadUserByUsername()方法即可。

    • 思路分析:

      没有认证(没有登录),执行UserDetailsService接口自定义实现类中loadUserByUsername()方法,根据用户名在数据库中查询数据,查询到了数据,再完成密码的比较。

1.2 返回值UserDetails
1.2.1 UserDetails接口

1.2.2 User实现类
  • User的全限定路径:

org.springframework.security.core.userdetails.User 此处经常和系统中自己开发的User类弄混。

  • 构造方法:

构造方法有两个。三个参数的构造方法实际上也是调用7个参数的构造方法。

3.自定义认证准备

2.1 准备流程
  1.  创建数据库表。
  2. 引入mybatis-plus,mysql,Spring Security相关依赖。
  3. 在配置文件中配置数据源和mybatis-plus相关配置。
  4. 创建实体类。
  5. UserServiceImp实现UserDetailsService接口,并重写loadUserByUsername方法。
  6. 创建配置类。将BCryptPasswordEncoder(实现PasswordEncoder接口 )交由Spring容器管理。
2.2 UserServiceImpl的编写
@Service
public class UserServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;/*** @param username  前端登录时提交的用户名* @return          用户的认证信息,要求必须为UserDetails接口的实现类* @throws UsernameNotFoundException  用户名没有找到时的异常*/@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();wrapper.eq(User::getUsername, username);User myUser = userMapper.selectOne(wrapper);if (myUser == null){throw new UsernameNotFoundException("用户名不存在");}/** org.springframework.security.core.userdetails.User为UserDetails接口的实现类。* 也可以自定义的User实现UserDetail接口提供对应的属性。* *///参数一:用户名  参数二:密码  参数三:权限(暂时不授权,创建个没有元素集合。不能指定null)ArrayList<GrantedAuthority> list = new ArrayList<>();org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(myUser.getUsername(), myUser.getPassword(), list);return user;}
}
2.3 PasswordEncoder接口实现类
@Configuration
public class SecurityConfig {//密码比较,加密器@Beanpublic PasswordEncoder getPwdEncoder() {return new BCryptPasswordEncoder();}
}

2.PasswordEncoder接口

Spring Security要求容器中必须有PasswordEncoder接口实现类对象。进行密码校验和密码加密。

2.1 介绍

 encode()

将密码进行加密。可以用在注册用户中,将用户提交的密码加密后再存储到数据库中。

matches()

用户登录时,将新提交的密码进行加密,加密后和数据库中存储的已经加密的密码进行校验。密码匹配,返回true;不匹配,返回false。

第1个参数:新提交的密码。第2个参数:数据库中存储的已经加密的密码。

upgradeEncoding() 用于判断是否需要对密码进行再次加密,以使得密码更加安全, 默认:false不需要。

2.2 接口实现类

Spring security中有多种实现类完成密码加密:

  1. MD5算法的Md5PasswordEncoder(不再被广泛使用 )。
  2. SHA 算法的ShaPasswordEncoder。
  3. BCrypt算法的BCryptPasswordEncoder。BCryptPasswordEncoder是Spring Security官方推荐的密码解析器
2.3 实现类BCryptPasswordEncoder
@SpringBootTest
class SpringsecurityApplicationTests {@Testvoid contextLoads() {BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();String encode = bpe.encode("123456");System.out.println(encode); boolean matches = bpe.matches("123456", encode);System.out.println(matches); }
}
2.4创建配置类
  • 创建配置类,将BCryptPasswordEncoder交由Spring容器管理。

@Configuration
public class SecurityConfig {//密码比较,加密器@Beanpublic PasswordEncoder getPwdEncoder() {return new BCryptPasswordEncoder();}
}

五、自定义登录页面(重点)

1. 创建登录页面

pring Security中不仅仅提供了登录页面,还支持用户自定义登录页面。

2. 修改配置类

  • 修改过滤器链中的配置

  1. 请求授权设置

    1. login.html 没有认证,可以被访问

    2. 其它请求没有认证,不可以被访问

  2. 自定义的登录的请求能够被拦截

    • 登录请求被拦截后,Spring Security会获取登录请求的用户名和密码,获取后调用自定义UserDetailsService接口实现类UserServiceImpl,从数据库中根据获取的用户名进行查询和后续的密码校验。

    • 注意:此过程不经过控制器。

    • 设置登录页面的访问路径

    • 设置登录请求的访问路径

    • 也可以设置登录成功后请求的资源

    • 也可以设置登录失败后请求的资源

  3. 自定义登录请求需要关闭CSRF。

@Configuration
public class SecurityConfig {//滤器链的相关设置@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {//请求授权设置。/** antMatchers():对指定的请求url进行控制* permitAll():允许访问* anyRequest():任意一个请求url的控制* authenticated():认证后便可以访问* */http.authorizeRequests().antMatchers("/login.html").permitAll()  //login.html不需要被认证.anyRequest().authenticated();  //其它任意的请求都必须被认证,必须认证(登录成功)后就可以直接访问//Form表单提交请求的处理。(可以为传统form表单提交,ajax提交)http.formLogin().loginPage("/login.html")           //登录页面对应的地址,退出登录功能时会使用.loginProcessingUrl("/user/login")  //登录的url,SpringSecurity会拦截该请求,执行登录的处理.successForwardUrl("/user/ok")      //登录成功跳转的资源。默认只接收post请求.failureForwardUrl("/user/err");    //登录失败跳转的资源.usernameParameter("uname")        //自定义用户名参数名.passwordParameter("pwd");         //自定义密码参数名//关闭csrf防护http.csrf().disable();return http.build();}//密码比较,加密器@Beanpublic PasswordEncoder getPwdEncoder() {return new BCryptPasswordEncoder();}
}

六、认证流程源码分析

1. UsernamePasswordAuthenticationFilter

  • 用户提交登录请求后执行UsernamePasswordAuthenticationFilter

2 . AuthenticationManager

  • ProviderManager为AuthenticationManager接口的实现类实现了authenticate方法

3. DaoAuthenticationProvider

  • 调用父类AbstractUserDetailsAuthenticationProvider中的authenticate方法

  • 接收到UserDetails接口实现类User对象后,继续进行相关验证

  • 认证通过后会调用createSuccessAuthentication方法,在该方法中new 了一个 UsernamePasswordAuthenticationToken,因为到这里认证已经通过了,所以将 authorities(授权数据) 注入进去,并设置 authenticated 为 true,已经被认证。  

4. AbstractAuthenticationProcessingFilter

5. 流程总结

  1. 用户在浏览器中随意输入一个URL。

  2. Spring Security 会判断当前是否已经被认证(登录)如果已经认证,正常访问URL。如果没有被认证跳转到loginPage()对应的URL中,显示登录页面。

  3. 用户输入用户名和密码点击登录按钮后,发起请求。

  4. 如果url和loginProcessingUrl()一样才执行登录流程。否则需要重新认证。

  5. 执行登录流程时首先被UsernamePasswordAuthenticationFilter进行过滤,取出用户名和密码,放入到容器(UsernamePasswordAuthenticationToken)中。根据usernameParameter和passwordParameter获取用户名和密码,如果没有配置这两个方法,默认为请求参数名username和password,把UsernamePasswordAuthenticationToken 交给 AuthenticationManager对象进行匹配管理,在当前方法中会进行认证方式匹配(AuthenticationProvider )

  6. 我们使用表单是AbstractUserDetailsAuthenticationProvider,再次调用retrieveUser()执行自定义登录逻辑UserDetailsService的实现类。返回数据库中保存当前用户信息,然后调用三次检查方法

    1. preAuthenticationChecks.check(user);(账号是否锁定,账号是否启用,账号是否过期)

    2. additionalAuthenticationChecks(user,authentication);(密码是否为null,密码是否正确)

    3. postAuthenticationChecks.check(user);(密码是否过期)

  7. 经过AbstractAuthenticationProcessingFilter中doFliter()进行跳转:

    1. 登录成功,执行onAuthenticationSuccess方法,重定向到指定的资源。

      • 通过session存储用户的认证信息。一个客户端会分配一个线程,在seesion中存储时为了保证线程安全,使用ThreadLocal存储认证信息。

        • ThreadLocal:

        • 存储在ThreadLocal中的数据可以保证线程安全。

    2. 登录失败,执行onAuthenticationFailure方法,请求转发到指定的资源。

    • 注意:如果没有配置成功和失败转发URL,会跳转到用户访问的URL。

七、退出登录

1. 创建退出登录

  • 退出登录的请求路径为logout,会被过滤器拦截,拦截后会跳转到登录页面。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><a href="/logout">退出登录</a>
</body>
</html>

2. 设置退出登录

  • 注意:退出登录后会清除认证信息,只有配置了放行的资源才能够跳转

//退出登录相关自定义(可以不用定义)
http.logout().logoutUrl("/mylogout")         //自定义退出访问的路径.logoutSuccessUrl("/user/login.html");  //自定义退出成功后跳转的资源       

3. logout流程源码分析

 

 

八、Remember Me

  • Spring Security 中Remember Me为 "记住我" 功能,Spring Security会自动把用户信息存储到数据源中,以后就可以不登录进行访问。

  • 用户只需要在登录表单中添加复选框,并且name="remember-me" value="true"。

1. 修改登录页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<form action="user/login" method="post">用户名:<input type="text" name="uname"> <br>密码:<input type="text" name="pwd"> <br>记住我:<input type="checkbox" name="remember-me" value="true"> <br><input type="submit">
</form>
</body>
</html>

2. 添加配置类

@Configuration
public class RememberMeConfig {@Autowiredprivate DataSource dataSource;@Beanpublic PersistentTokenRepository getPersistentTokenRepository() {JdbcTokenRepositoryImpl jdbcTokenRepositoryImpl=new JdbcTokenRepositoryImpl();jdbcTokenRepositoryImpl.setDataSource(dataSource);// 自动建表,第一次启动时需要,第二次启动时注释掉//jdbcTokenRepositoryImpl.setCreateTableOnStartup(true);return jdbcTokenRepositoryImpl;}
}

3. 修改SecurityConfig配置类

@Configuration
public class SecurityConfig {//注入UserDetailsService@Autowiredprivate UserDetailsService userDetailsService;//滤器链的相关设置@Bean                                                     //新添加,令牌库public SecurityFilterChain filterChain(HttpSecurity http, PersistentTokenRepository tokenRepository) throws Exception {// 其它配置需要添加 ...//remember Mehttp.rememberMe()// .tokenValiditySeconds(120)     //单位:秒。默认2周// .rememberMeCookieDomain("/")   //设置cookie的域.tokenRepository(tokenRepository).userDetailsService(userDetailsService);return http.build();}//密码比较,加密器@Beanpublic PasswordEncoder getPwdEncoder() {return new BCryptPasswordEncoder();}
}

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

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

相关文章

关于pytorch中的dim的理解

今天碰到一个代码看起来很简单&#xff0c;但是细究原理又感觉好像不太通不太对劲&#xff0c;就是多维tensor数据的操作&#xff0c;比如&#xff1a;y.sum(dim2)&#xff0c;乍一看很简单数据相加操作&#xff0c;但是仔细一想&#xff0c;这里在第3维度的数据到底是横向相加…

DevOps的发展史了解

DevOps的历史发展史可以追溯到2000年代初期&#xff0c;当时软件开发行业开始意识到&#xff0c;软件开发和IT运维之间的问题已经成为阻碍软件开发速度和效率的重要因素。在此之前&#xff0c;软件开发和IT运维是两个相对独立的过程&#xff0c;开发人员开发软件并将其交付给运…

【计算机】硬件体系结构

计算机硬件体系结构 计算机硬件体系结构是指计算机系统的组织和设计&#xff0c;包括处理器、内存、输入/输出设备、总线等各个组件之间的连接和协作方式。硬件体系结构定义了计算机如何执行指令、存储和检索数据以及与外部设备通信。以下是计算机硬件体系结构的主要组成部分&…

[OpenWrt]RAX3000一根线实现上网和看IPTV

背景&#xff1a; 1.我家电信宽带IPTV 2.入户光猫&#xff0c;桥接模式 3.光猫划分vlan&#xff0c;将上网信号IPTV信号&#xff0c;通过lan口&#xff08;问客服要光猫超级管理员密码&#xff0c;具体教程需要自行查阅&#xff0c;关键是要设置iptv在客户侧的vlan id&#…

Socks5与代理IP技术探析:构建安全高效的网络通信

1. Socks5协议的技术内幕 1.1 握手与身份验证 Socks5协议的握手阶段通过版本协商和灵活的身份验证方式建立安全连接。这确保了通信的可靠性和用户身份的安全。 1.2 数据传输机制 Socks5通过代理实现数据传输&#xff0c;支持TCP和UDP协议&#xff0c;为用户提供了高度灵活的…

FPGA设计流程:从概念到实现的详细指南

目录 引言 1. 概念阶段 1.1 确定需求 1.2 制定规范 2. 设计阶段 2.1 系统设计 2.2 硬件描述语言&#xff08;HDL&#xff09;编写 2.3 仿真验证 3. 综合与优化 3.1 逻辑综合 3.2 布局与布线 4. 实现与调试 4.1 下载与配置 4.2 调试与验证 5. 部署与维护 5.1 系统…

vite与webpack的一些技巧

通常项目里会有很多的api与导入导出&#xff0c;为了避免过多而提高效率 vue3的使用过程中&#xff1a;可以读取文件然后异步的获取挂载在属性上面 虽然我知道按需的好处&#xff0c;但有时候很急效率至少就没办法考虑性能&#xff0c; 所以频繁的导出与import导入使用变量申明…

Zibll子比主题最新学习版

Zibll子比主题5.7.1是一款为WordPress平台设计的优秀主题。它具有独特而富有吸引力的设计风格&#xff0c;同时提供了丰富的功能和卓越的性能&#xff0c;使您的网站在众多网站中脱颖而出。以下是对Zibll子比主题5.7.1的详细介绍。 &#xff08;这是我在“布谷鸟网址导航”上看…

minio可用性磁盘/节点故障恢复的研究

做poc真的很累。年初的报告拿出来按topic拿出来分享一下。 目的 通过模拟各类条件下的minio集群状态&#xff0c;确认minio是否符合官方“N/2硬盘在线&#xff0c;数据可读取&#xff1b;N/21硬盘在线&#xff0c;数据可读写”的描述。 同时通过停止minio集群中节点的服务停止…

粗到细语义(Coarse-to-Fine Semantics)

粗到细语义&#xff08;Coarse-to-Fine Semantics&#xff09;是一种深度学习模型的设计方法&#xff0c;它通过逐步细化的方式来理解文本中的语义信息。这种方法通常用于文本分类、情感分析、问答等任务中。 在粗到细语义中&#xff0c;模型首先从整体上理解文本的大致意思&a…

【计算机设计大赛作品】诗意千年—唐朝诗人群像的数字展现_附源码—信息可视化赛道获奖项目深入剖析【可视化项目案例-20】

🎉🎊🎉 你的技术旅程将在这里启航! 记得看本专栏里顶置的可视化宝典导航贴哦! 🚀🚀 本专栏为可视化专栏,包含现有的所有可视化技术。订阅专栏用户在文章底部可下载对应案例完整源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你…

Arris VAP2500 list_mac_address未授权RCE漏洞复现

0x01 产品简介 Arris VAP2500是美国Arris集团公司的一款无线接入器产品。 0x02 漏洞概述 Arris VAP2500 list_mac_address接口处命令执行漏洞,未授权的攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限,进而控制整个web服务器。 0x03 复现环境 FOFA…

AIGC与数据安全

数据安全是指保护数据不受非法或恶意的访问、使用、修改、泄露或破坏的能力。数据安全可能导致以下几个方面的问题&#xff1a; ✜ 数据泄露&#xff1a;AIGC可能泄露隐私信息&#xff0c;如姓名、地址、身份证号、银行账号等&#xff0c;危害用户安全和利益。AIGC可能生成包含…

值得收藏:一份完整的Mysql高性能优化规范建议

数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字&#xff08;如果表名中包含关键字查询时&#xff0c;需要将其用单引号括起来&#xff09; 数据库对象的命名要能做到见名识意&#xff0c;并且最后不要超过32个…

ES客户端RestHighLevelClient的使用

1 RestHighLevelClient介绍 默认情况下&#xff0c;ElasticSearch使用两个端口来监听外部TCP流量。 9200端口&#xff1a;用于所有通过HTTP协议进行的API调用。包括搜索、聚合、监控、以及其他任何使用HTTP协议的请求。所有的客户端库都会使用该端口与ElasticSearch进行交互。…

如何在不同的操作系统和架构中构建Go应用程序

在软件开发中,重要的是要考虑要编译二进制文件的操作系统和底层处理器架构。由于在不同的操作系统/体系结构平台上运行二进制文件通常很慢,甚至不可能,因此通常的做法是为许多不同的平台构建最终的二进制文件,以最大限度地吸引程序的受众。然而,当用于开发的平台与要部署程…

【PTA刷题】 顺序表(删除)(代码+详解)

文章目录 题目C代码详解 题目 已知一组数据&#xff0c;采用顺序存储结构存储&#xff0c;其中所有的元素为整数。设计一个算法&#xff0c;删除元素值在[x,y]之间的所有元素 输入格式: 输入包含三行数据&#xff0c;第一行是表中元素个数&#xff0c;第二行是顺序表的各个元素…

OpenCV极坐标变换函数warpPolar的使用

学更好的别人&#xff0c; 做更好的自己。 ——《微卡智享》 本文长度为1702字&#xff0c;预计阅读4分钟 前言 前阵子在做方案时&#xff0c;得了几张骨钉的图片&#xff0c;骨科耗材批号效期管理一直是比较麻烦的&#xff0c;贴RFID标签成本太高&#xff0c;所以一般考虑还是…

Crow:黑魔法 添加路由3 绑定lambda

Crow:黑魔法2 new_rule_tagged实现模板参数的绑定-CSDN博客 template<uint64_t N> typename black_magic::arguments<N>::type::template rebind<TaggedRule>& new_rule_tagged(const std::string& rule) {using RuleT = typename black_magic::arg…

07.Go 流程控制

流程控制是Go语言中必不可少的一部分&#xff0c;也是整个编程基础的重要一环。Go语言的流程控制语句和其他编程语言的流程控制语句有些不同&#xff0c;主要体现在Go语言没有do-while语句。Go语言常用的流程控制包括if语句、switch语句、for语句及goto语句等&#xff0c;switc…