SpringSecurity学习笔记

本以为是总结,最后写成了笔记,所以还是需要更加的努力啊。

开始的时候看了一遍官方文档,然后只看懂了加密器。

然后又学了一个尚硅谷的视频,虽然这个教程是在讲一个项目,但我没有听懂(应该是我自己的问题)

代码 https://gitee.com/pilearn/learning-spring-security

中文版文档 https://www.springcloud.cc/spring-security.html

尚硅谷视频链接 https://www.bilibili.com/video/BV15a411A7kP

什么是SpringSecurity

Security是Spring全家桶中一个安全框架,他的扩展能力非常的强,底层是一条过滤器链。通过简单的配置就可以使用,但通过自己的DIY,可以把每个权限细化到每个链接上去。

shiro没有学,但只推荐学一个安全框架

这里搭建的学习项目都是使用SpringBoot

获取SpringSecurity

你可以在maven官网获取最新版本

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-security</artifactId>
  4. <version>2.4.2</version>
  5. </dependency>

开始一个SpringBoot项目

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.4.2</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.pipihao</groupId>
  12. <artifactId>securitylearn</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>securitylearn</name>
  15. <description>Demo project for Spring Boot</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>com.alibaba</groupId>
  22. <artifactId>druid</artifactId>
  23. <version>1.1.21</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-starter-security</artifactId>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-web</artifactId>
  36. </dependency>
  37. <dependency>
  38. <groupId>org.mybatis.spring.boot</groupId>
  39. <artifactId>mybatis-spring-boot-starter</artifactId>
  40. <version>2.1.4</version>
  41. </dependency>
  42. <dependency>
  43. <groupId>mysql</groupId>
  44. <artifactId>mysql-connector-java</artifactId>
  45. <scope>runtime</scope>
  46. </dependency>
  47. <dependency>
  48. <groupId>org.projectlombok</groupId>
  49. <artifactId>lombok</artifactId>
  50. <optional>true</optional>
  51. </dependency>
  52. <dependency>
  53. <groupId>org.springframework.boot</groupId>
  54. <artifactId>spring-boot-starter-test</artifactId>
  55. <scope>test</scope>
  56. </dependency>
  57. <dependency>
  58. <groupId>org.springframework.security</groupId>
  59. <artifactId>spring-security-test</artifactId>
  60. <scope>test</scope>
  61. </dependency>
  62. </dependencies>
  63. <build>
  64. <plugins>
  65. <plugin>
  66. <groupId>org.springframework.boot</groupId>
  67. <artifactId>spring-boot-maven-plugin</artifactId>
  68. <configuration>
  69. <excludes>
  70. <exclude>
  71. <groupId>org.projectlombok</groupId>
  72. <artifactId>lombok</artifactId>
  73. </exclude>
  74. </excludes>
  75. </configuration>
  76. </plugin>
  77. </plugins>
  78. </build>
  79. </project>

项目配置文件

  1. server:
  2. port: 8001
  3. spring:
  4. datasource:
  5. url: jdbc:mysql://localhost:3306/demo?serverTimezone=Asia/Shanghai
  6. username: root
  7. password: root
  8. driver-class-name: com.mysql.cj.jdbc.Driver
  9. thymeleaf:
  10. cache: false
  11. # 因为Thymeleaf很多有默认配置,所以只关了这个缓存,方便刷新

数据库文件

数据库版本为 8.0


运行项目


登录

用户名:user

密码:控制台输出的这密码

配置Security

方法一:通过配置文件修改登录账号密码

  1. spring:
  2. security:
  3. user:
  4. name: xx
  5. password: xx

方法二:通过自定义配置SecurityConfig配置类

WebSecurityConfigurerAdapter 类是是Security内置提供了一个默认身份验证的抽象类,继承此抽象类实现configure方法则可以对验证操作实现DIY。[于官方文档 6.3 标题可见]

UserDetailsService接口:查询数据库用户名和密码过程

  • 创建类继承UsernamePasswordAuthenticationFilter,重写三个方法

    *
  • 创建类实现UserDetailService,编写查询数据过程,返回User对象,这个User对象是安全框架提供对象。
  • PasswordEncoder: 数据加密接口,用于返回User对象里面的密码加密

方法三:自定义配置类UserDetailsService

定义不验证链接

  1. @Override
  2. protected void configure(HttpSecurity http) throws Exception {
  3. /*
  4. 使用and()方法表示关闭XML标记的Java配置,它允许我们继续配置父标记。如果您阅读代码,它也是有道理的。我想配置授权请求并配置表单登录并配置HTTP基本身份验证。
  5. */
  6. http
  7. .authorizeRequests()
  8. .antMatchers("/","/no").permitAll() //可以直接访问的路径
  9. .anyRequest().authenticated()
  10. .and()
  11. .formLogin()
  12. .loginPage("/login.html") //配置登录路径
  13. .loginProcessingUrl("/doLogin")
  14. .defaultSuccessUrl("/hallo")
  15. .permitAll()
  16. ; //设置 登录的网页
  17. http.csrf().disable(); //如果注释了这一行,全部要用_csrf的对象来验证了
  18. }

配置访问权限/角色

如果是配置访问角色则使用是hasRole与hasAnyRole

这里非常建议点一下看一下hasRole的源码 使用Role的时候,User的权限列表是需要加ROLE_前缀的

这里直接使用的是hasAnyAuthority,还有一个方法是hasAuthority

前者可以配置多个权限,而后者只能配置一个权限

接口只是显示一个字符串

  1. @GetMapping("test")
  2. public String sayTest(){
  3. return "Test";
  4. }

SecurityConfig代码

  1. @Override
  2. protected void configure(HttpSecurity http) throws Exception {
  3. /*
  4. 使用and()方法表示关闭XML标记的Java配置,它允许我们继续配置父标记。如果您阅读代码,它也是有道理的。我想配置授权请求并配置表单登录并配置HTTP基本身份验证。
  5. */
  6. http
  7. .authorizeRequests()
  8. .antMatchers("/","/no").permitAll() //可以直接访问的路径
  9. .antMatchers("/test").hasAnyAuthority("admin") // 访问权限
  10. .anyRequest().authenticated()
  11. .and()
  12. .formLogin()
  13. .loginPage("/login.html") //配置登录路径
  14. .loginProcessingUrl("/doLogin")
  15. .defaultSuccessUrl("/hallo")
  16. .permitAll()
  17. ; //设置 登录的网页
  18. http.csrf().disable(); //如果注释了这一行,全部要用_csrf的对象来验证了
  19. }

UserDetailsImpl代码

  1. @Override
  2. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  3. if(StringUtils.isEmpty(username)){
  4. throw new RuntimeException("用户名不能为空");
  5. }
  6. IUser iUser= userMapper.getUserByUsername(username);
  7. if(iUser == null){
  8. throw new UsernameNotFoundException("无此用户");
  9. }
  10. /*此处查询用户角色*/
  11. List<GrantedAuthority> grantedAuthorityList =
  12. AuthorityUtils.createAuthorityList("admin"); // 权限的列表
  13. return new User(iUser.getUsername(),bCryptPasswordEncoder.encode(iUser.getPassword()),grantedAuthorityList);
  14. }

自定义403界面

  1. // 在此方法内加上一行 protected void configure(HttpSecurity http)
  2. http.exceptionHandling().accessDeniedPage("/unauth.html");

权限注解

@Secured

判断是否有角色,这里匹配的角色需要加前缀ROLE_

  1. @GetMapping("update")
  2. @Secured({"ROLE_manager"})
  3. public String update(){
  4. return "update";
  5. }

使用其功能时需要在application类上开起

  1. @SpringBootApplication
  2. @MapperScan("com.pipihao.securitylearn.mapper")
  3. @EnableGlobalMethodSecurity(securedEnabled = true)
  4. public class SecuritylearnApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(SecuritylearnApplication.class, args);
  7. }
  8. }

UserDetailsServiceImpl

  1. List<GrantedAuthority> grantedAuthorityList =
  2. AuthorityUtils.createAuthorityList("admin","ROLE_manager");

@PreAuthorize & @PostAuthorize

此注解即有权限验证功能,又有角色验证功能

  1. @GetMapping("pre1")
  2. @PreAuthorize("hasAnyRole('ROLE_manager')")
  3. public String prePost1(){
  4. return "prePost1";
  5. }
  6. @GetMapping("pre2")
  7. @PreAuthorize("hasAnyAuthority('admin')")
  8. public String prePost2(){
  9. return "prePost2";
  10. }
  1. @SpringBootApplication
  2. @EnableGlobalMethodSecurity(prePostEnabled = true)
  3. public class SecuritylearnApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(SecuritylearnApplication.class, args);
  6. }
  7. }

@PostAuthorize 与@PreAuthorize的区别就是,Pre会先拦截后执行,而PostAuthorize是先执行,后拦截

所以我例子中没有过多的讲

@PreFilter & @PostFilter

Pre是过滤上传的数据,Post过滤返回的数据

  1. @GetMapping("list")
  2. @PostFilter("filterObject.username != 'admin' ")
  3. public List<IUser> list(){
  4. List<IUser> iUsers = new ArrayList<>();
  5. iUsers.add(new IUser(1,"admin","123"));
  6. iUsers.add(new IUser(2,"user","123"));
  7. return iUsers;
  8. }
  9. // Applicationo类上还是要加上下面这个注解,并设置属性值
  10. @EnableGlobalMethodSecurity(prePostEnabled = true)

效果图

上传则是同理,通过注解写好判断,然后测试即可,注:PreFilter过滤的也只是集合和数组

用户注销

  1. /*配置退出登录*/
  2. http.logout().logoutUrl("/logout").logoutSuccessUrl("no").permitAll();

登录后,直接通过浏览器,访问此路径即可(是的,就是如此)

  1. location.href='/logout';

自动登录

下面是尚硅谷老师写的原理图和执行流程

如果是微服务,则把数据库改成redis,把cookie改成jwt生成的token

Security 中的一个类内JdbcTokenRepositoryImpl

的常量CREATE_TABLE_SQL

  1. create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, token varchar(64) not null, last_used timestamp not null)

有兴趣的可以看看源码 没兴趣的直接在你使用的数据库内执行上面这行sql创建一个保存登录信息的表

JdbcTokenRepositoryImpl 是PersistentTokenRepository实现类

下面这种写那么应该是多态了

  1. @Autowired
  2. private DataSource dataSource;
  3. @Bean
  4. public PersistentTokenRepository persistentTokenRepository(){
  5. JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
  6. jdbcTokenRepository.setDataSource(dataSource);
  7. //jdbcTokenRepository.setCreateTableOnStartup(true); 设置启动时创建自动登录表
  8. return jdbcTokenRepository;
  9. }

SecurityConfig的方法

  1. @Override
  2. protected void configure(HttpSecurity http) throws Exception {
  3. /*自定义403链接*/
  4. http.exceptionHandling().accessDeniedPage("/unauth.html");
  5. /*配置退出登录*/
  6. http.logout().logoutUrl("/logout").logoutSuccessUrl("/no").permitAll();
  7. /*
  8. 使用and()方法表示关闭XML标记的Java配置,它允许我们继续配置父标记。如果您阅读代码,它也是有道理的。我想配置授权请求并配置表单登录并配置HTTP基本身份验证。
  9. */
  10. http
  11. .authorizeRequests()
  12. .antMatchers("/","/no").permitAll() //可以直接访问的路径
  13. .antMatchers("/test").hasAnyAuthority("admin")
  14. .antMatchers("/unauth").hasAnyAuthority("xxx")
  15. .anyRequest().authenticated()
  16. .and()
  17. .formLogin()
  18. .loginPage("/login.html") //配置登录路径
  19. .loginProcessingUrl("/doLogin")
  20. .defaultSuccessUrl("/hallo")
  21. .permitAll()
  22. // -------------------就是下面这坨
  23. .and()
  24. .rememberMe().tokenRepository(persistentTokenRepository())
  25. .tokenValiditySeconds(60) // 自动保存的时间,秒为单位
  26. .userDetailsService(userDetailsService)
  27. ; //设置 登录的网页
  28. http.csrf().disable(); //如果注释了这一行,全部要用_csrf的对象来验证了
  29. }

下面是登录界面

  1. <form action="/doLogin" method="POST">
  2. user:<input type="text" name="username"><br>
  3. pswd:<input type="text" name="password"><br>
  4. <!--必须name=remember-me不然,是无法接收到是否自动登录的信息的-->
  5. 自动登录 <input type="checkbox" name="remember-me"><br>
  6. <input type="submit">
  7. </form>

然后在登录的时候打个勾,就可以自动登录了

在DB中会出现如下的信息

CSRF指令认证

第一步 把下面这一行注释了就开启了,也就是说他其实是默认开启的

如果没有关闭,则会NullPointerException

  1. //http.csrf().disable();

Spring Security CSRF 会针对Patch,Post,Put,Delete方法进行防护。(都是一些要更改数据的方法)

系统默认提供了一个csrfToken对象放在HttpSession中,也就是我们所见到了_csrf对象

此对象可以直接使用

开启CSRF后,则登录的时【POST】,也需要验证CSRF,而使用HttpSession则需要使用模板引擎,这里我们使用的是Thymeleaf而非JSP。(大同小异)

注:使用Thymeleaf的时候,类上的Controller注解不能写成RestController,不然无法生效的

  1. @Controller
  2. public class LoginController {
  3. @GetMapping("login")
  4. public String login(){
  5. return "login";
  6. }
  7. }
  1. <!doctype html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport"
  6. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <title>登录</title>
  9. </head>
  10. <body>
  11. <!--没加th:则不会有隐藏域自动生成-->
  12. <form th:action="'/doLogin'" method="POST">
  13. user:<input type="text" name="username"><br>
  14. pswd:<input type="text" name="password"><br>
  15. <!--必须name=remember-me不然,是无法接收到是否自动登录的信息的-->
  16. 自动登录 <input type="checkbox" name="remember-me"><br>
  17. <input type="submit">
  18. </form>
  19. </body>
  20. </html>

切记,默认开了CSRF,则每个表单中应当手动添加一个隐藏域

当Thymeleaf因为你使用了th,则自动给你生成了。

所以 th:action="'/doLogin'" 这样写可以省事

如下图

总结

本是总结,谁知还是变成了学习笔记。总结代表着会,笔记代表着只能用,说不出什么名堂。这是看第二遍,当然,这也会像我用正则一样,每次用正则的时候,都要学一遍正则。

或许SpringSecurity并不难,难的只是步骤有点多。

老师讲的很不错,多听几遍就会了。

关于提高技术,应该看文档,把他提供的API都自己看懂。像用Redist代替DB,这样的微服务中,使用,很有效率。

接下来,我还会继续学习Security,并出些新笔记,这最多算是一个听课笔记。

SpringBoot + Security学习笔记的更多相关文章

  1. SpringBoot + Spring Security 学习笔记(五)实现短信验证码+登录功能

    在 Spring Security 中基于表单的认证模式,默认就是密码帐号登录认证,那么对于短信验证码+登录的方式,Spring Security 没有现成的接口可以使用,所以需要自己的封装一个类似的 ...

  2. SpringBoot + Spring Security 学习笔记(三)实现图片验证码认证

    整体实现逻辑 前端在登录页面时,自动从后台获取最新的验证码图片 服务器接收获取生成验证码请求,生成验证码和对应的图片,图片响应回前端,验证码保存一份到服务器的 session 中 前端用户登录时携带当 ...

  3. SpringBoot + Spring Security 学习笔记(二)安全认证流程源码详解

    用户认证流程 UsernamePasswordAuthenticationFilter 我们直接来看UsernamePasswordAuthenticationFilter类, public clas ...

  4. SpringBoot 完整学习笔记免费分享

    从0到进阶,完全系统性的学习笔记 每次我都会反复拿来观看,因为我们总会有遗漏忘记的地方,但是笔记不会. 希望大家能好好利用它,以下是笔记截图! 以上只是其中的一项部分,这份笔记可以说含金量超高,绝对会 ...

  5. SpringBoot + Spring Security 学习笔记(四)记住我功能实现

    记住我功能的基本原理 当用户登录发起认证请求时,会通过UsernamePasswordAuthenticationFilter进行用户认证,认证成功之后,SpringSecurity 调用前期配置好的 ...

  6. SpringBoot + Spring Security 学习笔记(一)自定义基本使用及个性化登录配置

    官方文档参考,5.1.2 中文参考文档,4.1 中文参考文档,4.1 官方文档中文翻译与源码解读 SpringSecurity 核心功能: 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) ...

  7. Windows Security 学习笔记

    对于Windows 在 Security 方面的学习. 纯兴趣. UNIX 的另外开一条路线学习. 话说今天查gpedit.msc的资料的时候发现 M$ 官网上怎么连个文档都没有. 后来才点了 gpe ...

  8. Spring Security学习笔记

    Spring Web Security是Java web开发领域的一个认证(Authentication)/授权(Authorisation)框架,基于Servlet技术,更确切的说是基于Servle ...

  9. Spring Security学习笔记(三)

    之前提到过认证后怎么存放用户信息,令牌token是一种方式,session是另一种方式,这里介绍使用spring session data redis存储httpSession. 添加了以上依赖后,我 ...

随机推荐

  1. SpringMVC听课笔记(三:使用@RequestMapping映射请求)

    1. Spring MVC使用 @RequestMapping 注解为控制器指定可以处理哪些URL请求 2. 标注点: --类定义处:提供初步的请求映射信息.相对于WEB应用的根目录 --方法处:提供 ...

  2. 怎样将Sublime Text 设置成中文版(完整教程)

    1.打开Sublime Text,使用快捷键Shift+Ctrl+P,弹出查找栏,如图: 2.在搜索框中输入关键字 install ,出现下拉选项,点击选择其中的:Package Control: I ...

  3. SpringMVC数据校验并通过国际化显示错误信息

    目录 SpringMVC数据校验并通过国际化显示错误信息 SpringMVC数据校验 在页面中显示错误信息 通过国际化显示错误信息 SpringMVC数据校验并通过国际化显示错误信息 SpringMV ...

  4. 微信小程序分享之生成海报--canvas

    首先看文档 了解知识点~~(https://developers.weixin.qq.com/miniprogram/dev/component/) githup:https://github.com ...

  5. Codeforce 380A Sereja and Prefixes【二分】

    题意:定义两种操作 1 a ---- 向序列中插如一个元素a 2 a b ---- 将序列的前a个元素[e1,e2,...,ea]重复b次插入到序列中 经过一列操作后,为处于某个位置p的元素是多少.数 ...

  6. hdu1625 Numbering Paths (floyd判环)

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission ...

  7. python 实现AES加密和解密

    参考 https://blog.csdn.net/zhchs2012/article/details/79032656 AES加密算法是一种对称加密算法, 他有一个密匙, 即用来加密, 也用来解密 i ...

  8. Hyper-V安装CentOS修改分辨率

    grubby --update-kernel=ALL --args="video=hyperv_fb:1600x900" reboot https://blog.csdn.net/ ...

  9. WSL2 使用Docker运行.NET Core

    Docker的安装在前面说过了,此处就不说了,我们检查一下版本: 步入正题. 首先,我们为项目创建Dockerfile(无扩展名) 确保Docker是启动状态: 构建镜像,注意名称必须是全部小写(此处 ...

  10. aop详解与实战

    1. 什么是AOP aop:面向切面编程.采用横向机制. oop:面向对象编程.采用纵向机制. AOP,面向切面编程.就是通过某个切入点(比如方法开始.结束)向某个切面(被切的对象)切入环绕通知(需要 ...