• 1.SpringSecurity -快速入门、加密、基础授权


    SpringSecurity简介

    一、基本概念

    1.1 认证(Authentication)方式

    系统为什么要认证

    认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源

    什么是认证(登录)

    用户认证就是判断一个用户的身份是否合法的过程

    常见的用户身份认证方式

    • 用户名密码登录
    • 二维码登录
    • 手机短信登录
    • 指纹认证
    • 人脸识别

    1.2 会话(Session)介绍

    下面这个文章中有对session的理解:基于Session实现短信登录_c# 登录session怎么使用_我爱布朗熊的博客-CSDN博客

    过滤器与拦截器 - 登录校验与登录认证(JWT令牌技术)_jwt过滤器_我爱布朗熊的博客-CSDN博客

    用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。

    会话就是系统为了保持当前用户的登录状态所提供的机制

    常见的有基于session方式、基于token方式

    • 基于session的认证方式

      它的交互流程是,用户认证成功后,在服务端生成用户相关的数据保存在session(当前会话)中,发给客户端的sesssion_id 存放到 cookie 中,这样用户客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户的合法校验,当用户退出系统或session过期销毁时,客户端的session_id也就无效了。

    有一些用户在使用浏览器的时候会禁用Cookie,这会导致发一次请求,用户登录一次

    • 基于token的认证方式

      它的交互流程是,用户认证成功后,服务端生成一个token发给客户端,客户端可以放到 cookie 或 localStorage等存储中,每次请求时带上 token,服务端收到token通过验证后即可确认用户身份。可以使用Redis 存储用户信息(分布式中共享session)。

      基于session的认证方式由Servlet规范定制,服务端要存储session信息需要占用内存资源,客户端需要支持cookie;基于token的方式则一般不需要服务端存储token,并且不限制客户端的存储方式。如今移动互联网时代更多类型的客户端需要接入系统,系统多是采用前后端分离的架构进行实现,所以基于token的方式更适合。

    1.3 授权(Authorization)介绍

    为什么要授权(控制资源被访问)?

    因为不同的用户可以访问的资源不一样

    什么是授权(给用户颁发权限)?

    授权是用户认证通过后,根据用户的权限来控制用户访问资源的过程

    拥有资源的访问权限则正常访问,没有权限则拒绝访问

    1.4 RBAC

    RBAC(Role-Based Access Control) 基于角色的访问控制

    image-20230925222010168

    用户,角色,权限 本质:就是把权限打包给角色(角色拥有一组权限),又将角色分配给用户(用户拥有多个角色)。

    最少包括五张表 (用户表、角色表、用户角色表、权限表、角色权限表)

    二、SpringSecurity入门

    声明式(注解)的安全访问控制解决方案的安全框架

    提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作

    2.1 快速入门

    2.1.1 Maven坐标

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-securityartifactId>
        <version>2.4.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.1.2 接口

    @RestController
    @RequestMapping("/hello")
    public class HelloController {
    
        @GetMapping("/hello")
        private String hello(){
            return "hello";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    访问上面的接口就会出现下面的页面(登录)

    image-20231007105125017

    默认的用户名是User,密码是在控制台上的UUID

    image-20231007105319945

    登录上后便可以访问接口。

    之后不会使用这种方式

    我们也可以退出,访问IP:端口号/logout

    image-20231007105829342

    2.1.3 源码

    为什么默认的用户名是user并且密码是一串UUID

    如下代码所示

    image-20231007111234007

    2.2 配置文件配置用户名和密码

    在配置文件中配置如下信息

    spring:
      security:
        user:
          name: admin
          password: 123456
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此时我们再使用默认的用户就不行了,而且控制台也不会输出UUID形式的密码了

    image-20231007110802830


    Spring Security配置文件中默认配置用户是单一的用户,大部分系统都有多个用户,多个用户如何配置

    可以使用基于内存的多用户管理

    2.3 基于内存的多用户管理

    2.2 中配置的用户名和密码只能配置一个,但是我们的系统有许多的用户名和密码。

    /**
     * 自定义类实现用户详情服务接口
     *
     *   系统中默认是有这个UserDetailsService的,也就是默认的用户名(user)和默认密码(控制台生成的)
     *   如果在yaml文件中配置了用户名和密码,那在系统中的就是yaml文件中的信息
     *
     * 我们自定义了之后,就会把系统中的UserDetailsService覆盖掉
     */
    @Configuration
    public class MySecurityUserConfig  {
        /**
         * 根据用户名把用户的详情从数据库中获取出来,封装成用户细节信息UserDetailsService(包括用户名、密码、用户所拥有的权限)
         *
         * UserDetails存储的是用户的用户名、密码、去权限信息
         */
        @Bean
        public UserDetailsService userDetailsService() {
    //      用户细节信息,创建两个用户
    //      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainer
            UserDetails user1 =User.builder().username("zhangjingqi1").password("123456").roles("student").build();
            UserDetails user2 = User.builder().username("zhangjingqi2").password("123456789").roles("teacher").build();
    
    
    //      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsService
            InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
            userDetailsManager.createUser(user1);
            userDetailsManager.createUser(user2);
            return  userDetailsManager;
        }
    }   
    
    • 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

    上面的程序启动会报错,原因

    SpringSecurity强制要使用密码加密,当然我们也可以不加密,但是官方要求是不管你是否加密,都必须配置一个密码编码(加密)器

    /**
     * 自定义用户必须配置密码加密器。
     * NoOpPasswordEncoder.getInstance() 此实例表示不加密
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    此时用户名和密码就是user1与user2中配置的用户名和密码(此时配置文件中的用户名和密码会失效)

    image-20231014192803769

    image-20231014192744528



    UserDetails类如下所示:

    image-20231014190836999

    三、加密

    3.1 密码加密学习

    • 密码为什么要加密

    CSDN网站六百万用户信息外泄-月光博客 (williamlong.info)

    在加解密时一定要注意,我们要使用明文能加密成密文但是密文解密不成明文的加密算法

    如果密文能解密,那我们加密的效果其实不算太好,黑客照样还是可以破译

    image-20231014211903859

    • 加密的方式有哪些涉及到密码加密问题

      密码加密一般使用散列函数,又称散列算法,哈希函数,这些函数都是单向函数(从明文到密码,反之不行)

      常见的散列算法有MD5和SHA

      SpringSecurity提供了多种密码加密方案,基本上都实现了PasswordEncode接口官方推荐使用BCryptPasswordEncode

      image-20231014213450153

    image-20231014213514723

    • NoOpPasswordEncoder类已经过期了,而且还没有加密,怎么解决

    • 以学生身份登录,发现不但可以访问学生的页面,还可以访问教师的页面和管理员的页面,如何解决

      权限问题,后面解决

    • 如果要动态的创建用户,或者修改密码等(不是把用户名和密码写死到代码中),怎么办

    热疹信息存储到数据库中

    3.2 BCryptPasswordEncoder

            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            String encode1 = passwordEncoder.encode("123456");
            String encode2 = passwordEncoder.encode("123456");
            String encode3 = passwordEncoder.encode("123456");
            System.out.println(encode1);//$2a$10$hkaTFSnsEBYcZxXMrDpMQu.IiPM5ZAIQ63Vvkq01.oxxv0yVRmKly
            System.out.println(encode2);//$2a$10$nuPqwjhW0e/RZ.h3L1gZx.KanwUNQd4GEB2YoeB/LeVOhavcoBS7O
            System.out.println(encode3);//$2a$10$SPHV9tuI6JhgOwDO2hMR4eq43E5BGmYJDQJ5GltIuK7WSQqi1sHzm
    
    //      参数1:原文   参数2:密文
            boolean result1 = passwordEncoder.matches("123456", encode1);
            boolean result2 = passwordEncoder.matches("123456", encode2);
            System.out.println(result1);//true
            System.out.println(result2);//true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    补充断言的知识

    如果result1的结果是true的话,运行时的标记就是”√“,反之则是“×”

    assertTrue(result1);//期望result1为true
    assertFalse(result2);//期望result2为true
    
    • 1
    • 2

    以下就是错误的情况

    image-20231014220215113

    我们可以将PasswordEncoder放入到Bean工厂中

    /**
     * 配置密码加密器
     * NoOpPasswordEncoder.getInstance() 此实例表示不加密
     * BCryptPasswordEncoder() 会加密
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    修改我们之前的程序

        @Bean
        public UserDetailsService userDetailsService() {
    //      用户细节信息,创建两个用户
    //      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainer
            UserDetails user1 = User.builder().username("zhangjingqi-1").password(passwordEncoder().encode("123456")).roles("student").build();
            UserDetails user2 = User.builder().username("zhangjingqi-2").password(passwordEncoder().encode("123456")).roles("teacher").build();
    
    //      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsService
            InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
            userDetailsManager.createUser(user1);
            userDetailsManager.createUser(user2);
            return  userDetailsManager;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    四、权限信息

    4.1 获取登录用户信息

    关于已经验证实体的详情被存储到安全性上下文中(SpringContext)

    image-20231014222351220

    如果用户名和密码正确,说明认证成功

    此时会把认证信息放到Authentication中,再把Authentication放到SecurityContext中

    然后可以通过安全上下文持有器SecurityContextHolder获取安全上下文

    /**
     * 获取用户登录信息的方式
     */
    @RestController
    @Slf4j
    public class CurrentLoginUserController {
    
        /**
         * import org.springframework.security.core.Authentication;
         * 一旦登录成功,访问下面的请求就可以得到authentication
         *
         * Authentication 继承 Principal
         *
         */
        @GetMapping("/getLoginUser1")
        public Authentication getLoginUser1(Authentication authentication) {
            return authentication;
        }
    
    
    
        /**
         *import java.security.Principal;
         * 一旦登录成功,访问下面的请求就可以得到principal
         */
        @GetMapping("/getLoginUser2")
        public Principal getLoginUser2(Principal principal) {
            return principal;
        }
    
        /**
         * 一旦我们登陆成功,框架就会把我们的信息放到安全性上文中SpringContext
         * 所以我们可以通过安全性上文SpringContext获取用户信息
         */
        @GetMapping("/getLoginUser3")
        public Principal getLoginUser3() {
    //      通过安全上下文持有器获取安全上下文
            return SecurityContextHolder.getContext().getAuthentication();
        }
    
    }
    
    • 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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    访问:localhost:8080/getLoginUser1

    “name”用户名

    “credentials”凭据,其实就是密码,这里是null的原因就是直接给展示密码太不安全了,所以显示为null

    “authorities”权限信息,授权,权限

    “principal”中的内容就是代码UserDetails中定义的内容

    image-20231014224745740

    "accountNonExpired"账户是否未过期,true表示未过期

    "accountNonLocked"账户是否未锁定,true表示未锁定

    "credentialsNonExpired"凭证是否未过期,true表示未过期,这里的凭证一般是指密码
    **“enabled”**账户是否可用,true表示可用

    只有当"accountNonExpired"、“accountNonLocked”、“credentialsNonExpired”、"enabled"都为true时,账户才能使用

    image-20231014223719223

    4.2 配置用户权限

    如下图所示,便是给用户配置权限

    image-20231015151149649

    其中roles可以配置多个角色,其有一个可变数组,这样来说一个用户可以配置多个角色

    UserDetails user1 = User.builder().username("zhangjingqi-1").password(passwordEncoder().encode("123456")).roles("student","manager").build();
    
    • 1

    image-20231015151234272

    下面来配置一下用户的权限

        @Bean
        public UserDetailsService userDetailsService() {
    //      用户细节信息,创建两个用户
    //      此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainer
            UserDetails user1 = User.builder()
                    .username("zhangjingqi-1")
                    .password(passwordEncoder().encode("123456"))
    //               配置用户角色
                    .roles("student", "manager") //角色到系统中会变成权限的,比如这里会变成ROLE_student,ROLE_manager
    //               配置用户权限. student:delete权限处理学生的删除,student:add权限处理学生的添加
                    .authorities("student:delete","student:add")
                    .build();
            
            UserDetails user2 = User.builder()
                    .username("zhangjingqi-2")
                    .password(passwordEncoder().encode("123456"))
    //              配置权限
                    .authorities("teacher:delete", "teacher:add")
    //              配置角色
                    .roles("teacher")
                    .build();
    
    //      InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsService
            InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
            userDetailsManager.createUser(user1);
            userDetailsManager.createUser(user2);
            return userDetailsManager;
        }
    
    • 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

    登录zhangjingqi-1账号,访问localhost:8080/getLoginUser3

    我们发现,JSON串中“authorities”的内容是中配置的”authorities“,而没有将“roles”变成权限

    image-20231015152408310

    之后再登录zhangjingqi-2账号访问localhost:8080/getLoginUser3,我们发现下面的JSON串中”authorities“是在代码中配置的“roles”角色信息转换成的权限

    image-20231015152855592

    所以配置用户权限我们得出一个结论:

    • 在代码中配置“authorities“与“roles”时,谁再后面谁执行,后者会覆盖前者;

    • 配置的”roles“角色信息,在前面添加一个“ROLE_”前缀就会变成权限信息

    • 系统不会给配置的”authorities“权限信息添加任何前缀

    4.3 针对URL授权

    此控制级别只在Controller层

    虽然我们实现了认证功能,但是受保护的资源是默认的,默认所有认证(登录)用户均可以访问所有资源,不能根据实际情况进行角色管理

    实现授权功能,需重新WebSecurityConfigurerAdapter中的一个configure方法

    虽然之前我们配置了用户角色和用户权限,但是用户登录上之后依然可以随便访问,比如说“student”角色可以访问“teacher”角色对应的功能。

    4.3.1 拒绝任何请求

    如下代码所示:表示拒绝任何http请求

    虽然可以使用zhangjingqi-1或zhangjingqi-2认证成功登录,但是Controller不让访问,并且包括springSecurity框架中的login也会被屏蔽掉

    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        /**
         * 重写 configure(HttpSecurity http)方法
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
           http.authorizeRequests()//授权http请求
                   .anyRequest()//任何请求
                   .denyAll();//拒绝
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    访问http://localhost:8080/login如下所示

    image-20231015155702659

    4.3.2 允许登录表单

    为了可以访问http://localhost:8080/login,我们可以使用下面的一个配置

        /**
         * 重写 configure(HttpSecurity http)方法
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
           http.authorizeRequests()//授权http请求
                   .anyRequest()//任何请求
                   .denyAll();//拒绝
    
            http.formLogin().permitAll();//允许表单登录
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    此时就可以看到下面的登录界面了,但是如果访问其他请求,就会被拒绝

    image-20231015160916199

    4.3.3 允许任何请求

        /**
         * 重写 configure(HttpSecurity http)方法
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http.authorizeRequests()//授权http请求
                    .anyRequest()//任何请求
                    .permitAll();//允许任何请求
    
    
            http.formLogin().permitAll();//允许表单登录
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.3.4 匹配请求

    zhangjingqi-1对应的权限:student:delete、student:add

    zhangjingqi-2对应的权限:ROLE_teacher

    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        /**
         * 重写 configure(HttpSecurity http)方法
         */
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http.authorizeRequests()//授权http请求
                    .mvcMatchers("/student/**")// 匹配/student开头的请求
                    .hasAnyAuthority("student:add")// 拥有student:add权限的用户可以访问上面的url
    
                    .mvcMatchers("/teacher/**") // 匹配/teacher/**开头的请求
                    .hasAnyAuthority("ROLE_teacher")//拥有ROLE_teacher权限的用户可以访问/teacher/**开头的url
    
                    .anyRequest()// 任何请求
                    .authenticated()//需要验证。注意:没有配置的url,只要登录成功就可以访问
            ;
    
            http.formLogin().permitAll();//允许表单登录
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    使用zhangjingqi-1访问一下localhost:8080/student/hello

    image-20231015162519777

    使用zhangjingqi-1访问一下localhost:8080/hello/hello

    image-20231015162537580

    使用zhangjingqi-1访问一下localhost:8080/teacher/hello

    image-20231015162553881

    使用zhangjingqi-2访问一下http://localhost:8080/student/hello

    image-20231015162750496

    使用zhangjingqi-2访问一下localhost:8080/hello/hello

    image-20231015162537580

    使用zhangjingqi-2访问一下localhost:8080/teacher/hello

    image-20231015162818021

    4.3.5 总结

    • 匹配请求的三种方式
    .mvcMatchers("/student/**")
    
    • 1
    .regexMatchers("/student/**")
    
    • 1
    .anyMatchers("/student/**")
    
    • 1
    • 判断权限的五种方式

    推荐第一种

    .hasAuthority("ROLE_teacher") //是否有单个权限,参数只能写一个权限
    
    • 1
    .hasAnyAuthority("ROLE_teacher","student:add")//是否有其中的任意一个权限
    
    • 1
    .access( "hasAuthority('student:query') or  hasAuthority('student:add')")
    
    • 1
    .hasRole("student") // 是否有单个角色
    
    • 1
    .hasAnyRole("student") //是否有其中的某个角色
    
    • 1
    • 先写匹配路径,再写对应的权限

    4.4 针对方法进行授权

    下面 通过更灵活的配置方法安全,我们先通过@EnableGlobalMethodSecurity开启基于注解的安全配置

    4.4.1 抽象类

    public interface TeacherService {
        String add();
    
        String update();
    
        String delete();
    
        String query();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4.4.2 实现类

    @Slf4j
    @Service
    public class TeacherServiceImpl implements TeacherService {
    
        //预授权注解,此处采用表达式的形式。
        //如果有teacher:add权限,才会执行下面这个方法;反之不会访问
        @PreAuthorize("hasAuthority('teacher:add')")
        @Override
        public String add() {
            log.info("添加教师成功");
            return "添加教师成功";
        }
    
        //只要有teacher:update或teacher:add权限其中之一,便可以执行下面的方法
        @PreAuthorize("hasAnyAuthority('teacher:update','teacher:add')")
        @Override
        public String update() {
            log.info("修改教师成功");
            return "修改教师成功";
        }
    
        @PreAuthorize("hasAuthority('teacher:delete')")
        @Override
        public String delete() {
            log.info("删除教师成功");
            return "删除教师成功";
        }
    
        @PreAuthorize("hasAuthority('teacher:query')")
        @Override
        public String query() {
            log.info("查询教师成功");
            return "查询教师成功";
        }
    }
    
    • 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
    • 33
    • 34
    • 35

    4.4.3 teacher的Controller

    @RestController
    @RequestMapping("/teacher")
    public class TeacherController {
    
        @Resource
        private TeacherService teacherService;
    
    
        @GetMapping("/query")
        public String queryInfo() {
            return teacherService.query();
        }
    
        @GetMapping("/add")
        public String addInfo() {
            return teacherService.add();
        }
    
        @GetMapping("/update")
        public String updateInfo() {
            return teacherService.update();
        }
    
        @GetMapping("/delete")
        public String deleteInfo() {
            return teacherService.delete();
        }
    }
    
    • 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

    4.4.4 用户详情服务接口配置类

    @Configuration
    public class MySecurityUserConfig {
        /**
         * 根据用户名把用户的详情从数据库中获取出来,封装成用户细节信息UserDetails(包括用户名、密码、用户所拥有的权限)
         * 

    * UserDetails存储的是用户的用户名、密码、去权限信息 */ @Bean public UserDetailsService userDetailsService() { // 用户细节信息,创建两个用户 // 此User是SpringSecurity框架中的public class User implements UserDetails, CredentialsContainer UserDetails user1 = User.builder() .username("zhangjingqi-1") .password(passwordEncoder().encode("123456")) // 配置用户角色 .roles("student") //角色到系统中会变成权限的,比如这里会变成ROLE_student,ROLE_manager .build(); UserDetails user2 = User.builder() .username("zhangjingqi-2") .password(passwordEncoder().encode("123456")) // 配置权限 .authorities("teacher:query") .build(); UserDetails user3 = User.builder() .username("admin") .password(passwordEncoder().encode("123456")) // 配置权限 .authorities("teacher:query","teacher:add","teacher:update","teacher:delete") .build(); // InMemoryUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService,其中UserDetailsManager继承UserDetailsService InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager(); userDetailsManager.createUser(user1); userDetailsManager.createUser(user2); userDetailsManager.createUser(user3); return userDetailsManager; } /** * 配置密码加密器 * NoOpPasswordEncoder.getInstance() 此实例表示不加密 * BCryptPasswordEncoder() 会加密 */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }

    • 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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    4.4.5 安全配置

    WebSecurityConfig这个地方其实是URL的权限配置

    预授权:在访问方法之前判断有无权限(使用量最大)

    后授权:访问完方法后再判断有无权限

    //@Configuration
    //开启全局方法安全。 prePostEnabled = true 表示预授权和后授权开启
    //此注解中包含@Configuration注解,所以不用重复标识
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http.authorizeRequests()//授权http请求
                    .anyRequest() //任何请求
                    .authenticated();//都需要认证
    
            http.formLogin().permitAll();//允许表单登录
    
    //      或者下面这种形式
    //        http.authorizeRequests()//授权http请求
    //                .anyRequest() //任何请求
    //                .authenticated()//都需要认证
    //                .and()
    //                .formLogin().permitAll();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4.4.6 测试

    用户admin,访问localhost:8080/teacher/query

    image-20231016213447361

    用户admin,访问localhost:8080/teacher/add

    image-20231016213506529

    用户zhangjingqi-2,访问localhost:8080/teacher/query

    image-20231016213447361

    用户zhangjingqi-2,访问localhost:8080/teacher/add

    image-20231016213634402

    用户zhangjingqi-1,访问localhost:8080/teacher/query

    image-20231016213716614

  • 相关阅读:
    ubuntu 18.04安装自己ko驱动&& 修改secure boot
    MongoDB第一话 -- Docker安装MongoDB以及Springboot集成MongoDB
    C++ 异常处理 重新throw变量时的事件
    信息学奥赛研究1:竞赛时间表、学习规划
    SpringSecurity 全部
    【MindSpore易点通】调优精度之低阶API使用动态LossScale
    C语言基础(下)
    堪称一绝!阿里技术人都用的 Nginx 笔记手册,应用到架构齐全
    数据库——《数据定义》
    卷积神经网络 异常检测,卷积神经网络故障检测
  • 原文地址:https://blog.csdn.net/weixin_51351637/article/details/133870484