spring security
阅读数:210 评论数:0
跳转到新版页面分类
python/Java
正文
一、概述
SpringSecurity中认证(Authentication)和授权(Authorization)是分开的,认证是判断一个用户是否为合法用户,授权是访问控制。
在SpringSecurity中,认证和授权都是基于过滤器完成的。
默认过滤器并不是直接放在 Web 项目的原生过滤器链中,而是通过一个
FlterChainProxy 来统一管理。
二、AuthenticationManager
public interface AuthenticationManager {
// 返回Authentication表示认证成功,抛出异常,表示失败
Authentication authenticate(Authentication authentication)throws AuthenticationException;
}
AuthenticationManager 主要实现类为 ProviderManager,在 ProviderManager 中管理了众多 AuthenticationProvider 实例。
在一次完整的认证流程中,Spring Security 允许存在多个 AuthenticationProvider ,用来实现多种认证方式,这些 AuthenticationProvider 都是由 ProviderManager 进行统一管理的。
三、Authentication
认证以及认证成功的信息主要是由 Authentication 的实现类进行保存的
public interface Authentication extends Principal, Serializable {
// 获取用户权限信息
Collection<? extends GrantedAuthority> getAuthorities();
// 获取用户凭证信息,一般指密码
Object getCredentials();
// 获取用户详细信息
Object getDetails();
// 获取用户身份信息,用户名、用户对象等
Object getPrincipal();
// 用户是否认证成功
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}
四、SecurityContextHolder
SecurityContextHolder 用来获取登录之后用户信息。
Spring Security 会将登录用户数据保存在 Session 中。
SecurityContextHolder有三种工作模式
MODE_THREADLOCAL(默认) | 使用ThreadLocal保存信息,此方式也是非常适合Servlet web应用,因为对于一个请求的处理,不管经历了多少Filter,都是在一个线程中进行的。但是对于不同的servlet request,使用的线程不一定是同一个线程 |
MODE_GLOBAL | 数据保存在一个静态变量中,其存储载体是一个静态变量,可以在多线程环境下使用,但是用的比较少。 |
MODE_INHERITABLETHREADLOCAL | 其存储载体为InheritableThreadLocal,InheritableThreadLocal继承ThreadLocal,多了一个特性,就是在创建子进程的时候,会自动的将父进程中的数据复制到子进程中去,实现了子进程能够获取父进程数据的功能。 |
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication()
UserDetails principal = (UserDetails)authentication.getPrincipal();
五、AccessDecisionManager
访问决策管理器,用来决定此次访问是否被允许。
六、AccessDecisionVoter
访问决定投票器。
AccesDecisionVoter 和 AccessDecisionManager 都有众多的实现类,在 AccessDecisionManager 中会换个遍历 AccessDecisionVoter,进而决定是否允许用户访问,因而 AccesDecisionVoter 和 AccessDecisionManager 两者的关系类似于 AuthenticationProvider 和 ProviderManager 的关系。
七、ConfigAttribute
用来保存授权时的角色信息。
在 Spring Security 中,用户请求一个资源(通常是一个接口或者一个 Java 方法)需要的角色会被封装成一个 ConfigAttribute 对象,在 ConfigAttribute 中只有一个 getAttribute方法,该方法返回一个 String 字符串,就是角色的名称。
八、Spring Security提供的过滤器
默认情况下Spring Boot 在对 Spring Security 进入自动化配置时,会创建一个名为 SpringSecurityFilerChain 的过滤器,并注入到 Spring 容器中
名称 | 作用 | 默认是否加载 |
ChannelProcessingFilter | 过滤请求协议 HTTP 、HTTPS | NO |
CorsFilter | 处理跨域问题 | NO |
OAuth2AuthorizationRequestRedirectFilter | 处理 OAuth2 认证重定向 | NO |
X509AuthenticationFilter | 处理 X509 认证 | NO |
Saml2WebSsoAuthenticationRequestFilter Saml2WebSsoAuthenticationFilter |
处理 SAML 认证 | NO |
AbstractPreAuthenticatedProcessingFilter | 处理预认证问题 | NO |
CasAuthenticationFilter | 处理 CAS 单点登录 | NO |
OAuth2LoginAuthenticationFilter |
处理 OAuth2 认证 | NO |
BearerTokenAuthenticationFilter | 处理 OAuth2 认证的 Access Token | NO |
OAuth2AuthorizationCodeGrantFilter |
处理OAuth2认证中授权码 | NO |
OpenIDAuthenticationFilter | 处理 OpenID 认证 | NO |
ConcurrentSessionFilter | 处理 Session 有效期 | NO |
DigestAuthenticationFilter | 处理 HTTP 摘要认证 | NO |
JaasApiIntegrationFilter | 处理 JAAS 认证 | NO |
RememberMeAuthenticationFilter |
处理 RememberMe 登录 | NO |
SwitchUserFilter | 处理账户切换 | NO |
WebAsyncManagerIntegrationFilter |
将 WebAsyncManger 与 SpringSecurity 上下文进行集成 | YES |
SecurityContextPersistenceFilter |
在处理请求之前,将安全信息加载到 SecurityContextHolder 中 | YES |
HeaderWriterFilter |
处理头信息加入响应中 | YES |
CsrfFilter |
处理 CSRF 攻击 | YES |
LogoutFilter |
处理注销登录 | YES |
UsernamePasswordAuthenticationFilter |
处理表单登录 | YES |
DefaultLoginPageGeneratingFilter |
配置默认登录页面 | YES |
DefaultLogoutPageGeneratingFilter |
配置默认注销页面 | YES |
BasicAuthenticationFilter |
处理 HttpBasic 登录 | YES |
RequestCacheAwareFilter |
处理请求缓存 | YES |
AwareRequestFilter |
包装原始请求 | YES |
AnonymousAuthenticationFilter |
配置匿名认证 | YES |
SessionManagementFilter |
处理 session 并发问题 | YES |
ExceptionTranslationFilter |
处理认证/授权中的异常 | YES |
FilterSecurityInterceptor |
处理授权相关 | YES |
九、SpringBoot security auto configuration
1、默认的安装设置
为spring boot添加安全配置,只需要添加如下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
这会包含SecurityAutoConfiguration类,这包含初始化和默认的安全配置。
有一些预定义的属性:
spring.security.user.name
spring.security.user.password
如果不指定密码,那么会生成一个随机密码,在console输出中可以看到:
Using default security password: c8be15de-4488-4490-9dc6-fab3f91435c6
2、关闭Auto-Configuration
@SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class SpringBootSecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootSecurityApplication.class, args);
}
}
或者在配置文件中添加
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration
3、SpringBootWebSecurityConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnDefaultWebSecurity
@ConditionalOnWebApplication(type = Type.SERVLET)
class SpringBootWebSecurityConfiguration {
@Bean
@Order(SecurityProperties.BASIC_AUTH_ORDER)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http)
throws Exception {
http.authorizeRequests().anyRequest()
.authenticated().and().formLogin().and().httpBasic();
return http.build();
}
}
默认的生效条件:
class DefaultWebSecurityCondition extends AllNestedConditions {
DefaultWebSecurityCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })
static class Classes {
}
@ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })
static class Beans {
}
}
(1)条件一 classpath中存在 SecurityFilterChain.class, HttpSecurity.class
(2)条件二 没有自定义 WebSecurityConfigurerAdapter.class, SecurityFilterChain.class
十、WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter 这个类极其重要,它扩展 Spring Security 所有默认配置。
如果要对 Spring Security 进行自定义配置,就要自定义这个类实例,通过覆盖类中方法达到修改默认配置的目的。
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeHttpRequests()
.mvcMatchers("/login.html").permitAll()
.mvcMatchers("/index").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/doLogin")
.usernameParameter("uname")
.passwordParameter("passwd")
.successForwardUrl("/index") //forward 跳转 注意:不会跳转到之前请求路径
//.defaultSuccessUrl("/index") //redirect 重定向 注意:如果之前请求路径,会有优先跳转之前请求路径
.failureUrl("/login.html")
.and()
.csrf().disable();//这里先关闭 CSRF
}
}
|
|
|
|
|
|
successForwardUrl | 默认使用 forward 跳转 注意:不会跳转到之前请求路径 |
defaultSuccessUrl | 默认使用 redirect 跳转 注意:如果之前请求路径,会有优先跳转之前请求路径,可以传入第二个参数进行修改 |
十一、UserDetailService
用来修改默认认证的数据源信息。
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
默认情况下都会满足,此时Spring Security会提供一个 InMemoryUserDetailManager 实例。