##一步一步开启Spring Security(使用Spring Boot)

###创建一个SpringBoot项目

  • 输入Group 和 Artifact
  • 点击下面一排小字的 Switch to the full version.
  • 勾选 Security 和 Web俩个模块
  • 如图所示:
  • 找到项目中包下的 XXXApplication的那个java类, 为它填上三个注解
//相当于三个注解,以后再讲
	    @SpringBootApplication
	    //相当于ResponseBody 和 Controller 
	    @RestController
	    //在这个类中所使用的jar包都会被加载,而且提供默认配置 excludeName可以取消默认配置
	    @EnableAutoConfiguration
  • 现在在这个类里面添加一个方法
@RequestMapping("/")
		public String home(){
			return "MackyHuang First SpringBoot";
		}
  • 然后打开pom.xml,备注里面关于tomcat的代码
<!--<dependency>-->
			<!--<groupId>org.springframework.boot</groupId>-->
			<!--<artifactId>spring-boot-starter-tomcat</artifactId>-->
			<!--<scope>provided</scope>-->
		<!--</dependency>-->
  • 允许这个 XXXApplication类的main方法,我们就会看到springboot启动啦!
    ###关于SpringSecurity的配置与使用
  • 新建一个Config类 继承WebSecurityConfigurerAdapter,然后实现里面的三个方法,先简略的看一下代码再进行解释
@Configuration
		@EnableWebSecurity
		public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
		@Resource
		private UserServiceOwn serviceOwn;
		@Override
		protected void configure(HttpSecurity http) throws Exception {
		//允许主目录 / 的访问
		//check任何目录
		//允许注销
		//允许表单登陆
		//禁用csrf
		http.authorizeRequests()
		.antMatchers("/authorize", "/").permitAll()
		.anyRequest().authenticated()
		.and()
		.logout().permitAll()
		.and()
		.formLogin();
		http.csrf().disable();
		}
		
		//允许资源文件加载
		@Override
		public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
		}
		
		//Spring Security中密码的存储格式需要加密,所以需要这种格式
		//如果再数据库中
		//需要
		//auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
		@Override
		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
		.withUser("macky")
		.password(new BCryptPasswordEncoder().encode("123456"))
		.roles("ADMIN");
		
		auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
		.withUser("huang")
		.password(new BCryptPasswordEncoder().encode("123456"))
		.roles("ADMIN");
		
		auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
		.withUser("user")
		.password(new BCryptPasswordEncoder().encode("123456"))
		.roles("USER");
		
		//auth.userDetailsService(serviceOwn).passwordEncoder(new PasswordEncoderOwn());
		security默认的数据库操作
		//auth.jdbcAuthentication().usersByUsernameQuery("macky").authoritiesByUsernameQuery("admin").passwordEncoder(new BCryptPasswordEncoder());
		}
		}
  • 在看完代码以及注释以后(其实注释已经说明了大量的问题)
  • 第一个类
@Override
		protected void configure(HttpSecurity http) throws Exception {
	
		http.authorizeRequests()  
		.antMatchers("/authorize", "/").permitAll()  //允许主目录 / 的访问
		.anyRequest().authenticated() //check任何目录
		.and()
		.logout().permitAll()  //允许注销
		.and()  
		.formLogin();  //允许表单登陆
		http.csrf().disable();   //禁用csrf
		}
  • 这里 调用http, 进行了一系列匹配, 其中的csrf就是Cross-site request forgery跨站请求伪造
  • 第二个类
//    允许资源文件加载
	    @Override
	    public void configure(WebSecurity web) throws Exception {
	        web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
	    }
  • 这个类解决的是资源文件的,对于那些请求这些资源文件的请求进行忽略
  • 第三个类
//这里只介绍关于内存中的储存用户信息
		@Override
		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		//Spring Security中密码的存储格式需要加密,所以需要这种格式
		auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
		.withUser("macky")
		.password(new BCryptPasswordEncoder().encode("123456"))
		.roles("ADMIN");
		
		auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
		.withUser("huang")
		.password(new BCryptPasswordEncoder().encode("123456"))
		.roles("ADMIN");
		
		auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
		.withUser("user")
		.password(new BCryptPasswordEncoder().encode("123456"))
		.roles("USER");

		。。其实以上的内容,就是内存中创建一个用户信息,指定气密码的匹配器,然后指定用户名,密码和角色,这里我们创建了3个用户,俩个角色

		
		//auth.userDetailsService(serviceOwn).passwordEncoder(new PasswordEncoderOwn());
		security默认的数据库操作
		//auth.jdbcAuthentication().usersByUsernameQuery("macky").authoritiesByUsernameQuery("admin").passwordEncoder(new BCryptPasswordEncoder());
    }

###搞定了用户角色层次的,现在我们来配置一些访问的网页把(以下代码都在XXXApplication中,这里我们其实是把它当作是一个Controller,因为注解里面已经将它进行了配置)

@RequestMapping("/hello")
    public String hello(){
        return "hello world";
    }
  • 现在,让我们再允许一次项目,访问主目录 / 和 /hello 俩个页面,会发现, 主目录顺利访问了,然而,那个hello页面跳转到了登陆界面,这是为了啥子呢!
  • 回想我们前面的配置,会发现,我们在第一个config里面忽略了主目录的过滤,所有它是不需要验证的。
    ###让我们试试角色把
@PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping("/manage")
    public String manage(){
        return "Only admin can see this page";
    }
  • 并且!在XXXApplication类上面添加注解
@EnableGlobalMethodSecurity(prePostEnabled = true)
  • 添加了这段代码以后,继续访问,试着用不同的账号去登陆,然后查看结果
  • 拥有ADMIN角色的用户可以顺利访问,而拥有USER的用户出现没有权限访问的页面,返回403 无权限访问
  • 很明显,一来我们添加了俩个注解
    @PreAuthorize("hasRole('ROLE_ADMIN')")
  • 它使得我们的方法在访问前需要进行一定的操作,而我们在里面的参数是 hasRole,所有就是判断访问者的角色,而另外一个 @EnableGlobalMethodSecurity就是使得上面的这个注解生效

###让我们了解更多一些

  • 其实类似于@PreAuthorize 这样的注解不止这一个
//    这是方法进入前的判断,可以有内置的方法,也可以对参数进行判断
  @PreAuthorize("#index<10")	
  //    拦截方法调用后  这里还是遭到了拦截
  @PostAuthorize("returnObject==2")

  //    如果参数或者返回值是集合的时候,就可以使用*Filter注解,功能和上面的是一样的
  //    filterObject表示集合内的一个元素
  @PreFilter("filterObject<10")
  @PostFilter("filterObject<5")
  • 这俩组注解其实见文知意, 类似于AOP里面的方法处理前后的判断