Spring Security
Introduction
Spring Security是基于Spring的安全框架,Spring Security提供全面的安全性解决方案,同时在Web Request和Method处理身份认证和授权,在Spring Framework基础上,Spring Security充分利用了Soring的 DI和AOP特性,为应用系统提供了声明式的安全访问控制功能,是一个轻量级的框架,可以很好的与Spring及Spring MVC集成
核心功能
- 认证(Who are you?)
- 授权(What you can do?)
原理
基于Servlet Filter AOP实现认证和授权
Spring Security 最佳实践
使用系统自定义用户及yml中自定义的用户进行登录
- 创建Maven项目
- 加入依赖,SpringBoot web stater和security-stater
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-parent</artifactId> <version>2.1.5.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
3.创建启动SpringBoot启动类
@SpringBootApplication public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class,args); } }
4.创建controller包及Contrller控制器
@RestController public class HelloSecurityController { @GetMapping("/security") public String helloSecurity(){ return "Hello Spring Security!"; } }
5.启动SecurityApplication,控制台会生成密码,请看下图所示
浏览器地址栏输入http://localhost:8080/
输入用户名user及控制台生成的密码,即可登录系统访问HelloSecurityController
如果密码输入错误,则会有相应的提示
6.以上用户名密码都是由系统自动生成的,如果需要自定义用户名密码则需要在配置文件中进行配置,重新启动,输入设置的用户名密码即可登录
spring: security: user: name: admin password: admin
7.关闭登录验证对启动类进行修改,{}中可以放入多个配置类
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class}) public class SecurityApplication { public static void main(String[] args) { SpringApplication.run(SecurityApplication.class,args); } }
使用设置在内存中的用户进行登录
继承WebSecurityConfigurerAdapter,重写configure方法来控制安全管理的内容,将重写的类交由Spring IOC进行管理,可以自定义认证功能,重写是需要使用两个注解@Configuration和@EnableWebSecurity
@Configuration//表示该类是一个配置类,返回值是Java对象,由SpringIOC管理,相当于配置xml文件 @EnableWebSecurity //表示启用SpringSecurity安全框架功能 public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder pe = passwordEncoder(); // 设置内存中用户名和密码 auth.inMemoryAuthentication().withUser("IronMan").password(pe.encode("12345")).roles(); auth.inMemoryAuthentication().withUser("SpiderMan").password(pe.encode("12345")).roles(); auth.inMemoryAuthentication().withUser("Thor").password(pe.encode("thor")).roles(); } // 密码加密类,该类由SpringIOC进行管理,id默认为passwordEncoder @Bean public PasswordEncoder passwordEncoder(){ // 实现密码加密 return new BCryptPasswordEncoder(); } }
启动前关闭启动类上的exclude中的内容,启动成功后使用设置的用户名密码进行登录系统,如果改配置类中设置的密码没有加密会报错“java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"”
基于ROLE的身份认证
修改config包中的MyWebSecurityConfig类,给用户设置角色,代码如下:
/** * prePostEnabled = true表示可以使用@PreAuthorize注解和@PostAuthorize方法级别的注解 */ @Configuration//表示该类是一个配置类,返回值是Java对象,由SpringIOC管理,相当于配置xml文件 @EnableWebSecurity //表示启用SpringSecurity安全框架功能 @EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法级别的安全控制 public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder pe = passwordEncoder(); // 设置内存中用户名和密码,并设置角色,一个用户可以有多个角色 auth.inMemoryAuthentication().withUser("IronMan").password(pe.encode("12345")).roles("admin"); auth.inMemoryAuthentication().withUser("SpiderMan").password(pe.encode("12345")).roles("user"); auth.inMemoryAuthentication().withUser("Thor").password(pe.encode("thor")).roles("user","admin"); } // 密码加密类,该类由SpringIOC进行管理,id默认为passwordEncoder @Bean public PasswordEncoder passwordEncoder(){ // 实现密码加密 return new BCryptPasswordEncoder(); } }
修改HelloSecurityController,定义角色访问路径
@RestController public class HelloSecurityController { @GetMapping("/security") public String sayHello(){ return "使用内存中的用户信息进行认证"; } //指定user和admin都可以访问的方法 @GetMapping("/hello") @PreAuthorize(value = "hasAnyRole('admin','user')") public String helloUserAndAdmin(){ return "user和admin角色都可以访问"; } @GetMapping("/admin") @PreAuthorize(value = "hasAnyRole('admin')") public String helloAdmin(){ return "只有admin可以访问"; } }
启动应用,使用IronMan/12345访问/hello
访问/admin路径
重启tomcat,使用Thor/thor访问/hello
访问/admin