SpringSecurity基本原理&web权限方案

1. 基本原理:

  1. image-20221106162517079

  2. image-20221106163157990

  3. image-20221106163919356

2 .web权限方案-用户认证(设置用户名密码)

  1. 设置登录用户名和密码

    1. 方式一:通过配置文件

    properties为例

    1
    2
    3
    server.port=8111
    spring.security.user.name=atguigu
    spring.security.user.password=atguigu
    1. 方式二:通过配置类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
      import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;

      /**
      * @author : 其然乐衣Letitbe
      * @date : 2022/11/6
      */
      @Configuration
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
      // 加密
      String password = passwordEncoder.encode("123");
      auth.inMemoryAuthentication().withUser("lucy").password(password).roles("admin");
      }

      @Bean
      PasswordEncoder password() {
      return new BCryptPasswordEncoder();
      }
      }

    2. 方式三:自定义编写实体类

      在验证过程中,它会首先去找你的配置文件、配置类,如果发现其中有用户名和密码,那么它就会去找这个用户名和密码。但如果没有设置,它就会去找一个接口UserDetailsService,到这个接口你可以找通过表单提交或是查数据库或是其它方式设置的密码,然后去验证

      到UserDetailsService中找到你返回的用户名和密码和权限

      第一步:创建配置类,设置使用哪个userDetailsService实现类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      package com.atguigu.springsecurity.config;

      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
      import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.crypto.password.PasswordEncoder;

      /**
      * @author : 其然乐衣Letitbe
      * @date : 2022/11/6
      */
      @Configuration
      public class SecurityConfigTest extends WebSecurityConfigurerAdapter {

      @Autowired
      private UserDetailsService userDetailsService;

      @Override
      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.userDetailsService(userDetailsService).passwordEncoder(password());
      }

      @Bean
      PasswordEncoder password() {
      return new BCryptPasswordEncoder();
      }

      }

      第二步:编写实现类,返回User对象,User对象有用户名、密码和操作权限

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      package com.atguigu.springsecurity.service;

      import org.springframework.security.core.GrantedAuthority;
      import org.springframework.security.core.authority.AuthorityUtils;
      import org.springframework.security.core.userdetails.User;
      import org.springframework.security.core.userdetails.UserDetails;
      import org.springframework.security.core.userdetails.UserDetailsService;
      import org.springframework.security.core.userdetails.UsernameNotFoundException;
      import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.stereotype.Service;

      import java.util.List;

      /**
      * @author : 其然乐衣Letitbe
      * @date : 2022/11/6
      */
      @Service
      public class MyUserDetailsService implements UserDetailsService {

      @Override
      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("role");
      return new User("mary", new BCryptPasswordEncoder().encode("123"), auths);
      }
      }

      引用场景:

      一般实际开发中用的比较多的是第三种方式

      第一、二种方式:比如要超级管理员的时候,就只能用admin这个用户来登录,这个时候就而已用第一或第二种方式来配置。

      第三种方式:主要需求用于查数据库的时候

3. 自定义登录页面:

image-20221109105645708

4. 用户授权(基于权限 访问控制)

image-20221109110430894

image-20221109112842988

image-20221109112951312

image-20221109112800334

5. 自定义403页面

image-20221109113727226

image-20221109113838590

6. 用户授权(注解使用)

image-20221109113927963

image-20221109114120340

image-20221109115959853

image-20221109120027475

image-20221109120049901

image-20221109120114195

7.web权限方案—用户注销

image-20221109172751444

**8. **

8.1 web权限方案—自动登录(原理分析)

对应的教程视频:17-尚硅谷-SpringSecurity-web权限方案-自动登录(原理分析)_哔哩哔哩_bilibili

image-20221109184845677

8.1.1

image-20221109181738239

上图红框过程的原理和源码如下:

通过UsernamePasswordAuthenticationFilter来获取用户名和密码,之后验证验证成功后,在调用父类AbsxtractAuthenticationProcessingFilter里的successfulAuthentication方法,然后successfulAuthentication方法里面有RememberMeServices对象,在里面先用TokenRepository生成Token,然后把值放到浏览器Cookies中,并且用JdbcTokenRepositoryImpl里面封装的方法把生成的Token值写到数据库中

image-20221109180628066

image-20221109180549961

image-20221109181409113

8.1.2

image-20221109182017954

浏览器发送请求,就会调用这个RememberMeAuthenticationFilter过滤器,里面有dofilter里面的RememberMeServices对象的autoLogin方法进行自动登录

image-20221109183735806

image-20221109184615969

上图check方法的判断过程源码:

image-20221109184412419

8.2 web权限方案—自动登录(功能实现)

对应的教程视频:18-尚硅谷-SpringSecurity-web权限方案-自动登录(功能实现)_哔哩哔哩_bilibili

image-20221109191135868

image-20221109191228869

注意:image-20221109191528085

第一步:创建表

表不一定要我们自己创建,它可以自动我们生成,但是为了看得方便,所以自己可以创建一下,建表语句它里面有提供,可以自己去源码里面复制出来即可,如下:

image-20221109185400076

1
2
3
4
5
6
create table persistent_logins (
username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null
)

image-20221109185839379

image-20221109190502459

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 注入数据源
@Autowired
private DataSource dataSource;

// 配置对象
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
// 下面语句表示在使用时把表创建,而我们以及自己创建了,就不用了
// jdbcTokenRepository.setCreateTableOnStartup(true);
return jdbcTokenRepository;
}

9. CSRF的功能

CSRF的详解:Web漏洞之CSRF(跨站请求伪造漏洞)详解 - 知乎 (zhihu.com)

image-20221109203052376

在源码中的过程:就是验证之后,生成csrfToken,token存在session里面,每次携带token进行请求,然后拿着csrfToken跟session中的内容作比较,如果它们相同就可以访问,不相同就不能访问。主要代码就是在CsrfFilter里面:

image-20221109204032040

在配置类中如果添加下面这个语句就是关闭CSRF保护,不加上的话,springsecurity是默认开启CSRF保护的

image-20221109205622267