SpringSecurity | SpringSecurity基本使用以及常用注解

web权限配置的三种方式

通过配置文件

spring.security.user.name=root
spring.security.user.password=root

通过配置类的方式

package cn.knightzz.security.config;

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.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author knightzz
 * @date 2021/3/5 10:59
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String encodePassword = passwordEncoder.encode("root");
        auth.inMemoryAuthentication().withUser("root")
                .password(encodePassword).roles("admin");
    }
    
    @Bean
    PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

自定义实现类

  • 步骤

    第一步 : 创建配置 设置使用哪个 userDaoService实现类
    第二步 : 编写实现类 返回user对象(包括用户密码以及操作权限)
    
  • 代码

    第一步 : 创建相关配置

    package cn.knightzz.security.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 knightzz
     * @date 2021/3/5 11:51
     */
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        UserDetailsService userDetailsService;
    
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }
    
        @Bean
        PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
    }
    
    

    第二步 : 编写 Service 类

    package cn.knightzz.security.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 knightzz
     * @date 2021/3/5 11:57
     */
    @Service("userDetailsService")
    public class MyUserDetailsService implements UserDetailsService {
    
        @Override
        public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    
            // 模拟生成权限列表
            List<GrantedAuthority> auths = AuthorityUtils.
                    commaSeparatedStringToAuthorityList("role");
            // 账号 , 密码, 权限集合
            return new User("root" ,new BCryptPasswordEncoder().encode("root"),auths);
        }
    }
    
    

Controller认证

  • 添加相关配置

    package cn.knightzz.security.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.builders.HttpSecurity;
    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 knightzz
     * @date 2021/3/5 11:51
     */
    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        UserDetailsService userDetailsService;
    
        @Override
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }
    
        @Bean
        PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.formLogin() // 自定义自己编写的登陆页面
                    .loginPage("/login.html") // 登陆页面设置
                    .loginProcessingUrl("/user/login") // 登陆访问路径
                    .defaultSuccessUrl("/test/index").permitAll() // 登陆成功以后的跳转路径
                    .and().authorizeRequests()
                    .antMatchers("/", "/test/hello","/user/login").permitAll() // 设置哪些路径不需要认证可以直接访问
                    .anyRequest().authenticated()
                    .and().csrf().disable(); // 关闭csrf防护
        }
    }
    
    
  • 编写登陆页面

    登陆页面是在 static 目录下

    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登陆title>
    head>
    <body>
    
    
    <form action="/user/login" method="post">
        用户名 : <input name="username" type="text">
        <br />
        密码 : <input name="password" type="text">
        <br/>
        <input type="submit" value="login">
    form>
    
    body>
    html>
    
  • 测试

    http://localhost:8111/test/index
    

基于权限或者角色进行访问控制

hasAuthority

  • 第一步 在配置类中设置当前访问地址有哪些权限

    // 当前登录用户 必须有admin 权限才可以访问
    .antMatchers("/test/admin").hasAnyAuthority("admin")
    
  • 第二步 在 UserDetailsService 设置相应权限

     // 模拟生成权限列表
    List<GrantedAuthority> auths = AuthorityUtils.
                    commaSeparatedStringToAuthorityList("admin");
    // 账号 , 密码, 权限集合
            return new User("root" ,new BCryptPasswordEncoder().encode("root"),auths);
    
  • 测试

    http://localhost:8111/test/admin
    
    # 如果没有权限的话 结果 会报错 : 
    Whitelabel Error Page
    There was an unexpected error (type=Forbidden, status=403).
    

hasAnyAuthority

// 作用 
如果当前用户有提供的权限列表中的任何一个 返回 true
  • 配置

    // 当前用户必须要有权限列表中的任何一个都可以访问该路径
                    .antMatchers("/test/role").hasAnyAuthority("admin","superAdmin","role","user")
    
  • 第二步 在 UserDetailsService 设置相应权限

     // 模拟生成权限列表 用户角色使用 , 分割 
            List<GrantedAuthority> auths = AuthorityUtils.
                 commaSeparatedStringToAuthorityList("admin,user,superAdmin");
            // 账号 , 密码, 权限集合
            return new User("root" ,new BCryptPasswordEncoder().encode("root"),auths);
    
  • 测试

    http://localhost:8111/test/role
    

hasRole

  • 配置

    // 需要有 ROLE_user 角色才能访问
    .antMatchers("/test/role").hasRole("user")
    
  • 第二步 在 UserDetailsService 设置相应权限

    这里需要注意的是 角色列表 是 ROLE_ 开头的 否则会报错的

            
    // 模拟生成权限列表
            List<GrantedAuthority> auths = AuthorityUtils.
                    commaSeparatedStringToAuthorityList("ROLE_user");
    
  • 测试

    http://localhost:8111/test/role
    

hasAnyRole

使用方式 与 hasAnyAuthority 类似

自定义403 访问页面

  • 添加配置

            // 配置没有权限访问跳转到自定义页面
            http.exceptionHandling().accessDeniedPage("/403.html");
    
  • 创建403页面

    
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>403title>
    head>
    <body>
    
    <h1>403 ! 没有访问权限h1>
    body>
    html>
    
  • 测试

    http://localhost:8111/test/role
    

认证注解使用

@Secured

  • 作用

    用户必须 具有某个角色才能访问方法
        
    1. 使用前必须开启注解功能: 在启动类(或者配置类)上添加开启注解
    
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public class SpringSecurityWebApplication {}
    
    
    2. 需要注意的是 匹配字符串需要添加前缀 "ROLE"
        
    List<GrantedAuthority> auths = AuthorityUtils.
        commaSeparatedStringToAuthorityList("ROLE_admin,admin");
    
  • 第二步 : 在 Controller 的方法中添加注解

        @Secured({"ROLE_admin", "ROLE_manager"})
        @GetMapping("update")
        public String update(){
            return "hello update";
        }
    
  • 测试

    http://localhost:8111/test/update
    

@PreAuthorize

  • 作用

    注解适合进入方法前的验证
    
    1. 需要开启注解
        
    @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
    public class SpringSecurityWebApplication {}
    
    List<GrantedAuthority> auths = AuthorityUtils.
        commaSeparatedStringToAuthorityList("ROLE_admin,admin");
    
  • 第二步 : 在 Controller 的方法中添加注解

        @PreAuthorize("hasAnyAuthority('admin')")
        @GetMapping("auth")
        public String preAuthorize(){
            return "hello PreAuthorize";
        }
    
  • 测试

    http://localhost:8111/test/auth
    

@PostAuthorize

  • 作用

    1. 注解是在 方法执行后 才会验证权限的 
     
    2. 需要开启注解
        
    @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
    public class SpringSecurityWebApplication {}
    
    List<GrantedAuthority> auths = AuthorityUtils.
        commaSeparatedStringToAuthorityList("ROLE_admin,admin");
    
  • 第二步 : 在 Controller 的方法中添加注解

        @PostAuthorize("hasAnyAuthority('aaaa')")
        @GetMapping("post_auth")
        public String postAuthorize(){
            System.out.println("postAuthorize");
            return "hello postAuthorize";
        }
    
    
  • 测试

    http://localhost:8111/test/post_auth
    
    
    // 测试结果 
    
    403 ! 没有访问权限
        
    // 控制台会打印 hello postAuthorize
    

@PostFilter

  • 作用

    1. 权限验证之后对返回数据进行过滤 
        
        
    2. filterObject 对应返回值List的实体类 User 
       作用是 过滤掉 password 不等于 'admin01' 的数据 留下密码是 'admin01' 的数据
        
        @GetMapping("user")
        @PreAuthorize("ROLE_admin")
        @PostFilter("filterObject.password == 'admin01'")
        public List<User> getAllUser(){
    
  • 第二步 : 在 Controller 的方法中添加注解

        @GetMapping("user")
        @PreAuthorize("ROLE_admin")
        @PostFilter("filterObject.password == 'admin01'")
        public List<User> getAllUser(){
    
            List<User> users = new ArrayList<>();
            users.add(new User("admin01", "12345"));
            users.add(new User("admin02", "admin02"));
            return users;
        }
    
  • 使用 postman 测试

    http://localhost:8111/test/user
    
    // 测试结果
    [{"username":"admin02","password":"admin02"}]
    

@PreFilter

  • 作用

    1. 进入控制器之前对传入数据进行过滤
        
        
    2. 过滤掉 username 不等于 admin01 的数据 filterObject就是 users 的 User 类
        
        
        @GetMapping("filter")
        @PreAuthorize("hasAnyAuthority('ROLE_admin')")
        @PreFilter("filterObject.username == 'admin01'")
        public List<User> getTestPreFilter(List<User> users){}
    

你可能感兴趣的:(spring,spring,boot,spring,security)