• SpringSecurity03 基于内存验证


    1 需求

      现有一个编写好的系统,需要实现用户登录验证即可,同时根据用户的权限来限制用户可以访问的接口

    2 编写SpringSecurity配置类

      继承 WebSecurityConfigurerAdapter 类并重写configure 方法

      

    package cn.xiangxu.spring_security_system;
    
    //import cn.xiangxu.spring_security_system.service.MyUserService;
    import cn.xiangxu.spring_security_system.utils.MyPasswordEncoder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.builders.WebSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    /**
     * 权限服务类
     */
    @Configuration // 等同于XML中的beans
    @EnableWebSecurity // 开启webSecurity功能
    public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    
    //    @Autowired
    //    private MyUserService myUserService;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
            // 直接将用户信息和权限写死
            auth.inMemoryAuthentication()
                    .withUser("admin")
                    .password("123456")
                    .roles("ADMIN");
            auth.inMemoryAuthentication()
                    .withUser("wys")
                    .password("123456")
                    .roles("ADMIN");
            auth.inMemoryAuthentication()
                    .withUser("demo")
                    .password("123456")
                    .roles("USER");
    
    //        auth.userDetailsService(myUserService).passwordEncoder(new MyPasswordEncoder()); // 利用自定义的UserService进行管理
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/").permitAll() // 主页面请求拦截排除
                    .anyRequest().authenticated()  // 除主页面外的所有请求都会被拦截
                    .and()
                    .logout().permitAll() // 注销请求拦截排除
                    .and()
                    .formLogin(); // 设置使用表单登录的方式
            http.csrf().disable(); // 关闭csrf验证
        }
    
        @Override
        public void configure(WebSecurity web) throws Exception {
            // 拦截排除设置
            web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
        }
    
    
    }
    SpringSecurity配置类

       坑01:由于从springboot2.0.3开始使用的springsecurity的版本是5.x,这个版本需要提供一个PasswordEncoder的实例,否则就会如下错误

      解坑01之方法01:只需要创建一个PasswordEncoder的Bean并被spring容器所管理即可

        》创建一个实现了PasswordEncoder接口的实现类MyPasswordEncoder,在encode方法中编写加密算法,在matches方法中编写匹配算法

        》在配置文件中配置MyPasswordEncoder对应的Bean即可(在一个标注了@Configuration注解的类中添加下面的逻辑即可)

      解坑01之方法02:在创建内存用户的时候指定一个PasswordEncoder实例

        》创建一个实现了PasswordEncoder接口的实现类MyPasswordEncoder,在encode方法中编写加密算法,在matches方法中编写匹配算法

        》创建内存用户的时候直接指定PasswordEncoder即可

    3 编写一些接口用于测试

    package cn.xiangxu.spring_security_system;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    //@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启@PreAuthorize注解
    public class SpringSecuritySystemApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringSecuritySystemApplication.class, args);
        }
    
        @GetMapping(value = "/")
        public String home() {
            return "Welcome to study springSecurity.";
        }
    
        @GetMapping(value = "/hello")
        public String hello() {
            return "hello boy";
        }
    
    //    @PreAuthorize("hasRole('ROLE_ADMIN')") // 设定权限校验:只用ADMIN角色才能调用该接口
        @GetMapping("/roleAuth")
        public String role() {
            return "admin role";
        }
    }
    View Code

    4 请求测试接口

      利用硬编码的用户名和密码进行登录

      

    5 设置权限校验

      5.1 在控制类上添加 @EnableGlobalMethodSecurity 注解

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package org.springframework.security.config.annotation.method.configuration;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import org.springframework.context.annotation.AdviceMode;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    @Import({GlobalMethodSecuritySelector.class})
    @EnableGlobalAuthentication
    @Configuration
    public @interface EnableGlobalMethodSecurity {
        boolean prePostEnabled() default false;
    
        boolean securedEnabled() default false;
    
        boolean jsr250Enabled() default false;
    
        boolean proxyTargetClass() default false;
    
        AdviceMode mode() default AdviceMode.PROXY;
    
        int order() default 2147483647;
    }
    View Code

        @EnableGlobalMethodSecurity(prePostEnabled = true)

        代码解释:

          整个项目启用方法角色验证注解,prePostEnabled = true 表示启用@PreAuthorize 和 @PostAuthorize 两个方法角色验证注解(@PreFilter()@PostFilter() 也会被启用)

      5.2 在需要进行角色验证的接口上方添加 @PreAuthorize 注解

        @PreAuthorize("hasRole('ROLE_ADMIN')")

        代码解释:

          有该注解的方法只有角色是ADMIN的用户才可以访问

    package cn.xiangxu.spring_security_system;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.security.access.prepost.PostAuthorize;
    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启@PreAuthorize注解
    public class SpringSecuritySystemApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringSecuritySystemApplication.class, args);
        }
    
        @GetMapping(value = "/")
        public String home() {
            return "Welcome to study springSecurity.";
        }
    
        @GetMapping(value = "/hello")
        public String hello() {
            return "hello boy";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN')") // 设定权限校验:只用ADMIN角色才能调用该接口
        @GetMapping("/roleAuth")
        public String role() {
            return "admin role";
        }
    }
    View Code

    6 权限校验注解

      6.1 @PreAuthorize

        在执行方法之前进行权限校验

        6.1.1 角色验证

          例如:@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") // ADMIN USER 角色都有权限调用这个接口

    package cn.xiangxu.spring_security_system;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.security.access.prepost.PostAuthorize;
    import org.springframework.security.access.prepost.PostFilter;
    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.security.access.prepost.PreFilter;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启@PreAuthorize注解
    public class SpringSecuritySystemApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringSecuritySystemApplication.class, args);
        }
    
        @GetMapping(value = "/")
        public String home() {
            return "Welcome to study springSecurity.";
        }
    
        @GetMapping(value = "/hello")
        public String hello() {
            return "hello boy";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN')") // 设定权限校验:只用ADMIN角色才能调用该接口
        @GetMapping("/roleAuth")
        public String role() {
            return "admin role";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") // ADMIN 和 USER 角色都有权限调用这个接口
        @GetMapping("/test01")
        public String rest01() {
            return "test01";
        }
    }
    View Code

        6.1.2 参数验证01

          例如:@PreAuthorize("#id < 10") 

            代码解释: 方法必须有id参数,而且参数的值必须小于10

            

    package cn.xiangxu.spring_security_system;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.security.access.prepost.PostAuthorize;
    import org.springframework.security.access.prepost.PostFilter;
    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.security.access.prepost.PreFilter;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启@PreAuthorize注解
    public class SpringSecuritySystemApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringSecuritySystemApplication.class, args);
        }
    
        @GetMapping(value = "/")
        public String home() {
            return "Welcome to study springSecurity.";
        }
    
        @GetMapping(value = "/hello")
        public String hello() {
            return "hello boy";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN')") // 设定权限校验:只用ADMIN角色才能调用该接口
        @GetMapping("/roleAuth")
        public String role() {
            return "admin role";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") // ADMIN 和 USER 角色都有权限调用这个接口
        @GetMapping("/test01")
        public String rest01() {
            return "test01";
        }
    
        @PreAuthorize("#id < 10")
        @GetMapping("/test02/{id}")
        public String test02(@PathVariable("id") Integer id) {
            return "test02 -> 获取到的ID为:" + id;
        }
    }
    View Code

        6.1.3 参数验证03

          例如:@PreAuthorize("principal.username.equals(#username)")

            代码解释:方法必须有username参数,而且参数的值必须是登录用户的用户名

            

    package cn.xiangxu.spring_security_system;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.security.access.prepost.PostAuthorize;
    import org.springframework.security.access.prepost.PostFilter;
    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.security.access.prepost.PreFilter;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启@PreAuthorize注解
    public class SpringSecuritySystemApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringSecuritySystemApplication.class, args);
        }
    
        @GetMapping(value = "/")
        public String home() {
            return "Welcome to study springSecurity.";
        }
    
        @GetMapping(value = "/hello")
        public String hello() {
            return "hello boy";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN')") // 设定权限校验:只用ADMIN角色才能调用该接口
        @GetMapping("/roleAuth")
        public String role() {
            return "admin role";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") // ADMIN 和 USER 角色都有权限调用这个接口
        @GetMapping("/test01")
        public String rest01() {
            return "test01";
        }
    
        @PreAuthorize("#id < 10")
        @GetMapping("/test02/{id}")
        public String test02(@PathVariable("id") Integer id) {
            return "test02 -> 获取到的ID为:" + id;
        }
    
        @PreAuthorize("principal.username.equals(#username)")
        @GetMapping("/test03")
        public String test03(@RequestParam("username") String username) {
            return "test03 -> 获取到的username为:" + username;
        }
    }
    View Code

      6.2 @PostAuthorize

         在执行方法之后进行权限验证

         例如:@PostAuthorize("returnObject.equals('test04')")

            代码解释:判断方法的返回值是否等于 test04 , 如果是就通过验证,如果不是就验证失败

          技巧:returnObject代表方法的返回对象

           

    package cn.xiangxu.spring_security_system;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.security.access.prepost.PostAuthorize;
    import org.springframework.security.access.prepost.PostFilter;
    import org.springframework.security.access.prepost.PreAuthorize;
    import org.springframework.security.access.prepost.PreFilter;
    import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @SpringBootApplication
    @RestController
    @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启@PreAuthorize注解
    public class SpringSecuritySystemApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringSecuritySystemApplication.class, args);
        }
    
        @GetMapping(value = "/")
        public String home() {
            return "Welcome to study springSecurity.";
        }
    
        @GetMapping(value = "/hello")
        public String hello() {
            return "hello boy";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN')") // 设定权限校验:只用ADMIN角色才能调用该接口
        @GetMapping("/roleAuth")
        public String role() {
            return "admin role";
        }
    
        @PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')") // ADMIN 和 USER 角色都有权限调用这个接口
        @GetMapping("/test01")
        public String rest01() {
            return "test01";
        }
    
        @PreAuthorize("#id < 10")
        @GetMapping("/test02/{id}")
        public String test02(@PathVariable("id") Integer id) {
            return "test02 -> 获取到的ID为:" + id;
        }
    
        @PreAuthorize("principal.username.equals(#username)")
        @GetMapping("/test03")
        public String test03(@RequestParam("username") String username) {
            return "test03 -> 获取到的username为:" + username;
        }
    
        @PostAuthorize("returnObject.equals('test04')")
        @GetMapping(value = "/test04")
        public String test04(@RequestParam("info") String info) {
            return info;
        }
    }
    View Code

      6.3 @PreFilter

          在方法执行前对列表型的参数进行一些验证

        例如:@PreFilter("filterObject%2==0")

          ·代码解释:列表型的参数中的每个元素必须能被2整除

        技巧:filterObject 代表列表型的参数

       6.4 @PostFilter("filterObject%4 == 0")

         在方法执行后对返回的列表型对象进行一些验证

         例如:@PostFilter("filterObject%4 == 0")

           代码解释:列表型的返回对象中的每个元素必须能被4整除

         技巧:filterObject 代表列表型的返回对象

  • 相关阅读:
    c-free5
    node.js模块
    cd
    bower
    atom插件
    反射(操作MetaData)
    1.Html
    SQL语句 把一个表的数据复制到另外一个表里面
    Redis 可视化工具
    C# 多文件压缩包
  • 原文地址:https://www.cnblogs.com/NeverCtrl-C/p/7993157.html
Copyright © 2020-2023  润新知