在前两节中我们都是对url请求路径的来进行授权(基于角色,基于资源),当然security2以后还提供了基于方法的授权可以在任何@Configuration实列上通过@EnableGlobalMethodSecurity(securedEnabled = true)注解来启动方法的授权,下面会介绍@Secured(),@PreAuthorize()方法主角授权的使用
一,@Secured()的使用:这个注解配置在方法上是基于角色的授权模式,也就是只有用户拥有指定角色才能访问指定资源
第一步:在配置类上加上@EnableGlobalMethodSecurity(securedEnabled = true)注解,然后注释掉之前访问路径的配置
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class webSecurityConfig extends WebSecurityConfigurerAdapter {
    //密码编译比对方式
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    //访问路径配置
    @Override
    protected void configure(HttpSecurity http) throws java.lang.Exception {
        //hasAuthority : 基于资源授权  hasRole:基于角色授权
        http
        .csrf().disable() //去除csrf攻击的配置,以便除get请求方式,其他请求方式也能访问接口
        .authorizeRequests()
//        .antMatchers("/auth/hello").hasAuthority("resource_1")  //给访问的地址加上资源权限限制,只有用户有这个资源访问权限时才能访问
//        .antMatchers("/auth/home").hasAuthority("resource_2")
//        .antMatchers("/auth/admin").hasAuthority("resource_3")
        .antMatchers("/test/health").permitAll()     //此路径不需要经过过认证,可以不登录直接请求;注意不要放在上面的代码之前不然上面代码会失效,带通配符的url顺序也要注意 如 auth/login  应该放在auth/**的前面,也就是范围越大的越在后面
        .anyRequest().authenticated()                             //除配置的/test/health路径其他请求都需要认证
        .and()
        .formLogin() //允许表单登陆
                .successForwardUrl("/sys/login") //自定义表单登陆成功后的跳转路径
        .and()
                .logout()
                .logoutUrl("/sys/logOut");
    }
    //基于内存的用户配置
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws java.lang.Exception {
//        //创建三个用户到内存中,并给他们分配角色
//        auth.inMemoryAuthentication()
//                .withUser("zhangsan").password(this.passwordEncoder().encode("123456")).roles("GUEST");
//        auth.inMemoryAuthentication()
//                .withUser("lisi").password(this.passwordEncoder().encode("123456")).roles("USER");
//        auth.inMemoryAuthentication()
//                .withUser("wangwu").password(this.passwordEncoder().encode("123456")).roles("USER","ADMIN");
//    }
}
第二步:将用户授权改为角色授权(.roles(“ADMIN”))
@Service
public class SpringDataUserDetailsServiceImpl implements UserDetailsService {
	
	private static Logger logger = Logger.getLogger(SpringDataUserDetailsServiceImpl.class);
	
	@Autowired
    private UserDao userDao;
	
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    	
    	logger.info("++进入SpringDataUserDetailsServiceImpl++ username = "+username);
    	UserDo u = new UserDo();
    	u.setUserName(username);
    	UserDo user = userDao.selectOne(new QueryWrapper<>(u));
    	logger.info("查询到的用户信息:"+user.toString());
        if(Objects.isNull(user)){
        	//没有查到用户交给provider来抛异常
        	return null;
        }
        UserDetails userDetails = User
							        .withUsername(user.getUserName())
							        .password(user.getPassword())
							       // .authorities("resource_1")
									.roles("ADMIN")
							        .build();
        logger.info("++退出SpringDataUserDetailsServiceImpl++");
        return userDetails;
    }
}
第三步:在授权通过后需要访问的资源上的方法上面加上@Secured()注解
注意:注解里面的参数:如果是角色授权那么参数需要以ROLE开头如:“ROLE_XXXX”
@GetMapping("/auth/home")
@ResponseBody
@Secured("ROLE_USER")
public String test2(){
    logger.info("+++++++++++++++++++++++++++++++请求成功TEST_USER+++++++++++++++++++++++++++++++++++");
    return "USER";
}
@GetMapping("/auth/admin")
@ResponseBody
@Secured("ROLE_ADMIN")
public String test3(){
    logger.info("+++++++++++++++++++++++++++++++请求成功TEST_ADMIN+++++++++++++++++++++++++++++++++++");
    return "ADMIN";
}
第五步:测试,用户登陆因为用户角色是写死的每个用户登陆都是ADMIN角色,那么,用户只能访问test3方法,而不能访问test2方法
@Secured的其他参数:

二, @PreAuthorize / @PostAuthorize的使用:这两个注解的功能是差不多的,只是区别在于@PreAuthorize是在执行方法之前进行权限或角色的校验,而@PostAuthorize是在方法执行玩之后在进行校验,也就是校验的时机不一样
第一步:配置类上配置开启注解@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)   注意:记得配置prePostEnabled = true不然注解会不生效
@EnableWebSecurity
@Configuration
//@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class webSecurityConfig extends WebSecurityConfigurerAdapter {
    //密码编译比对方式
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    //访问路径配置
    @Override
    protected void configure(HttpSecurity http) throws java.lang.Exception {
        //hasAuthority : 基于资源授权  hasRole:基于角色授权
        http
        .csrf().disable() //去除csrf攻击的配置,以便除get请求方式,其他请求方式也能访问接口
        .authorizeRequests()
//        .antMatchers("/auth/hello").hasAuthority("resource_1")  //给访问的地址加上资源权限限制,只有用户有这个资源访问权限时才能访问
//        .antMatchers("/auth/home").hasAuthority("resource_2")
//        .antMatchers("/auth/admin").hasAuthority("resource_3")
        .antMatchers("/test/health").permitAll()     //此路径不需要经过过认证,可以不登录直接请求;注意不要放在上面的代码之前不然上面代码会失效,带通配符的url顺序也要注意 如 auth/login  应该放在auth/**的前面,也就是范围越大的越在后面
        .anyRequest().authenticated()                             //除配置的/test/health路径其他请求都需要认证
        .and()
        .formLogin() //允许表单登陆
                .successForwardUrl("/sys/login") //自定义表单登陆成功后的跳转路径
        .and()
                .logout()
                .logoutUrl("/sys/logOut");
    }
    //基于内存的用户配置
//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws java.lang.Exception {
//        //创建三个用户到内存中,并给他们分配角色
//        auth.inMemoryAuthentication()
//                .withUser("zhangsan").password(this.passwordEncoder().encode("123456")).roles("GUEST");
//        auth.inMemoryAuthentication()
//                .withUser("lisi").password(this.passwordEncoder().encode("123456")).roles("USER");
//        auth.inMemoryAuthentication()
//                .withUser("wangwu").password(this.passwordEncoder().encode("123456")).roles("USER","ADMIN");
//    }
}
第二步:接口配置注解
 	@GetMapping("/auth/hello")
    @ResponseBody
    //@Secured("ROLE_GUEST")
    //@PreAuthorize("isAnonymous()")
    public String test1(){
        logger.info("+++++++++++++++++++++++++++++++请求成功TEST_GUEST+++++++++++++++++++++++++++++++++++");
        return "GUEST";
    }
    @GetMapping("/auth/home")
    @ResponseBody
    //@Secured("ROLE_USER")
    @PreAuthorize("hasAuthority('resource_1')")  //拥有resource_1权限才能访问
    //@PreAuthorize("hasRole('USER')")  //@PreAuthorize基于角色的授权
    public String test2(){
        logger.info("+++++++++++++++++++++++++++++++请求成功TEST_USER+++++++++++++++++++++++++++++++++++");
        return "USER";
    }
    @GetMapping("/auth/admin")
    @ResponseBody
    //@Secured("ROLE_ADMIN")
    @PreAuthorize("hasAnyAuthority('resource_2','resource_3')") //拥有resource_2 或者 resource_3权限才能访问 
    //@PreAuthorize("hasAuthority('resource_2') and hasAuthority('resource_3')") //拥有resource_2 以及 resource_3权限才能访问
    //@PreAuthorize("hasRole('ADMIN')")  //@PreAuthorize基于角色的授权
    public String test3(){
        logger.info("+++++++++++++++++++++++++++++++请求成功TEST_ADMIN+++++++++++++++++++++++++++++++++++");
        return "ADMIN";
    }
test1方法不需要任何校验,test2方法需要有resource_1的权限,test3需要有resource_2和resource_3的权限
                  
                  
                  
                  
                            
本文介绍了SpringSecurity中基于方法授权的使用,包括@Secured和@PreAuthorize/@PostAuthorize。首先讲解了@Secured注解的配置步骤,通过角色进行授权,然后详细阐述了@PreAuthorize和@PostAuthorize的差异,它们分别在方法执行前后进行权限校验。
          
      
          
                
                
                
                
              
                
                
                
                
                
              
                
                
              
            
                  
					2208
					
被折叠的  条评论
		 为什么被折叠?
		 
		 
		
    
  
    
  
            


            