前言
Spring Security 比较复杂,愿与各位一起研究使用,有歧义的地方,欢迎指出,谢谢!
启动应用
1、clone 代码之后,进入 目录,启动应用
mvn spring-boot:run
2、demo 演示,地址:http://localhost:8080 账号 anoy 密码 pwd
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
/**
* 匹配 "/" 路径,不需要权限即可访问
* 匹配 "/user" 及其以下所有路径,都需要 "USER" 权限
* 登录地址为 "/login",登录成功默认跳转到页面 "/user"
* 退出登录的地址为 "/logout",退出成功后跳转到页面 "/login"
* 默认启用 CSRF
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/user/**").hasRole("USER")
.and()
.formLogin().loginPage("/login").defaultSuccessUrl("/user")
.and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/login");
}
/**
* 在内存中创建一个名为 "user" 的用户,密码为 "pwd",拥有 "USER" 权限
*/
@Bean
@Override
protected UserDetailsService userDetailsService() {
User.UserBuilder users = User.withDefaultPasswordEncoder();
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(users.username("user").password("pwd").roles("USER").build());
return manager;
}
}
@Controller
public class HomeController {
@GetMapping({"/", "/index", "/home"})
public String root(){
return "index";
}
@GetMapping("/login")
public String login(){
return "login";
}
}
@Controller
public class UserController {
@GetMapping("/user")
public String user(@AuthenticationPrincipal Principal principal, Model model){
model.addAttribute("username", principal.getName());
return "user/user";
}
}
相关解释说明
在 Spring boot 应用中使用 Spring Security,用到了 @EnableWebSecurity
注解,官方说明如下:
/**
* Add this annotation to an {@code @Configuration} class to have the Spring Security
* configuration defined in any {@link WebSecurityConfigurer} or more likely by extending
* the {@link WebSecurityConfigurerAdapter} base class and overriding individual methods:
*/
意思是说, 该注解和 @Configuration
注解一起使用, 注解 WebSecurityConfigurer
类型的类,或者利用@EnableWebSecurity
注解继承 WebSecurityConfigurerAdapter
的类,这样就构成了 Spring Security 的配置。
抽象类 WebSecurityConfigurerAdapter
一般情况,会选择继承 WebSecurityConfigurerAdapter
类,其官方说明如下:
/**
* Provides a convenient base class for creating a {@link WebSecurityConfigurer}
* instance. The implementation allows customization by overriding methods.
*
* <p>
* Will automatically apply the result of looking up
* {@link AbstractHttpConfigurer} from {@link SpringFactoriesLoader} to allow
* developers to extend the defaults.
* To do this, you must create a class that extends AbstractHttpConfigurer and then create a file in the classpath at "META-INF/spring.factories" that looks something like:
* </p>
* <pre>
* org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer
* </pre>
* If you have multiple classes that should be added you can use "," to separate the values. For example:
*
* <pre>
* org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer, sample.OtherThatExtendsAbstractHttpConfigurer
* </pre>
*
*/
意思是说 WebSecurityConfigurerAdapter
提供了一种便利的方式去创建 WebSecurityConfigurer
的实例,只需要重写 WebSecurityConfigurerAdapter
的方法,即可配置拦截什么URL、设置什么权限等安全控制。
方法 configure(AuthenticationManagerBuilder auth) 和 configure(HttpSecurity http)
Demo 中重写了 WebSecurityConfigurerAdapter
的两个方法:
/**
* 通过 {@link #authenticationManager()} 方法的默认实现尝试获取一个 {@link AuthenticationManager}.
* 如果被复写, 应该使用{@link AuthenticationManagerBuilder} 来指定 {@link AuthenticationManager}.
*
* 例如, 可以使用以下配置在内存中进行注册公开内存的身份验证{@link UserDetailsService}:
*
* // 在内存中添加 user 和 admin 用户
* @Override
* protected void configure(AuthenticationManagerBuilder auth) {
* auth
* .inMemoryAuthentication().withUser("user").password("password").roles("USER").and()
* .withUser("admin").password("password").roles("USER", "ADMIN");
* }
*
* // 将 UserDetailsService 显示为 Bean
* @Bean
* @Override
* public UserDetailsService userDetailsServiceBean() throws Exception {
* return super.userDetailsServiceBean();
* }
*
*/
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
this.disableLocalConfigureAuthenticationBldr = true;
}
/**
* 复写这个方法来配置 {@link HttpSecurity}.
* 通常,子类不能通过调用 super 来调用此方法,因为它可能会覆盖其配置。 默认配置为:
*
* http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
*
*/
protected void configure(HttpSecurity http) throws Exception {
logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
final 类 HttpSecurity
表1 HttpSecurity 常用方法及说明
方法 | 说明 |
| 用于基于 OpenId 的验证 |
| 将安全标头添加到响应 |
| 配置跨域资源共享( CORS ) |
| 允许配置会话管理 |
| 允许配置一个 |
| 配置基于容器的预认证。 在这种情况下,认证由Servlet容器管理 |
| 配置基于x509的认证 |
| 允许配置“记住我”的验证 |
| 允许基于使用 |
| 允许配置请求缓存 |
| 允许配置错误处理 |
| 在 |
| 将 |
| 添加 CSRF 支持,使用 |
| 添加退出登录支持。当使用 |
| 允许配置匿名用户的表示方法。 当与 |
| 指定支持基于表单的身份验证。如果未指定 |
| 根据外部OAuth 2.0或OpenID Connect 1.0提供程序配置身份验证 |
| 配置通道安全。为了使该配置有用,必须提供至少一个到所需信道的映射 |
| 配置 Http Basic 验证 |
| 在指定的Filter类的位置添加过滤器 |
类 AuthenticationManagerBuilder
/**
* {@link SecurityBuilder} used to create an {@link AuthenticationManager}. Allows for
* easily building in memory authentication, LDAP authentication, JDBC based
* authentication, adding {@link UserDetailsService}, and adding
* {@link AuthenticationProvider}'s.
*/
意思是,AuthenticationManagerBuilder
用于创建一个 AuthenticationManager
,让我能够轻松的实现内存验证、LADP验证、基于JDBC的验证、添加UserDetailsService
、添加AuthenticationProvider
。