WEB中的权限管理(二)
Spring security框架简介
简介
一个能够为基于Spring的企业应用系统提供声明式的安全訪问控制解决方式的安全框架(简单说是对访问权限进行控制嘛),应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。 spring security的主要核心功能为 认证和授权,所有的架构也是基于这两个核心功能去实现的。
框架原理
众所周知 想要对对Web资源进行保护,最好的办法莫过于Filter,要想对方法调用进行保护,最好的办法莫过于AOP。所以springSecurity在我们进行用户认证以及授予权限的时候,通过各种各样的拦截器来控制权限的访问,从而实现安全。
如下为其主要过滤器
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
LogoutFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
UsernamePasswordAuthenticationFilter
BasicAuthenticationFilter
框架的核心组件
SecurityContextHolder:提供对SecurityContext的访问
SecurityContext,:持有Authentication对象和其他可能需要的信息
AuthenticationManager 其中可以包含多个AuthenticationProvider
ProviderManager对象为AuthenticationManager接口的实现类
AuthenticationProvider 主要用来进行认证操作的类 调用其中的authenticate()方法去进行认证操作
Authentication:Spring Security方式的认证主体
GrantedAuthority:对认证主题的应用层面的授权,含当前用户的权限信息,通常使用角色表示
UserDetails:构建Authentication对象必须的信息,可以自定义,可能需要访问DB得到
UserDetailsService:通过username构建UserDetails对象,通loadUserByUsername根据userName获取UserDetail对象 (可以在这里基于自身业务进行自定义的实现 如通过数据库,xml,缓存获取等)
自定义安全配置的加载机制
前提
安全配置是基于自身业务需要,有关springSecrity安全框架的理解可以参考springSecurity安全框架介绍
自定义了一个springSecurity安全框架的配置类
继承WebSecurityConfigurerAdapter,重写其中的方法configure。在实现该类后,在web容器启动的过程中该类实例对象会被WebSecurityConfiguration类处理。
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AccessDeniedHandler accessDeniedHandler;
@Autowired
private CustAuthenticationProvider custAuthenticationProvider;
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/home", "/about","/img/*").permitAll()
.antMatchers("/admin/**","/upload/**").hasAnyRole("ADMIN")
.antMatchers("/order/**").hasAnyRole("USER","ADMIN")
.antMatchers("/room/**").hasAnyRole("USER","ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(custAuthenticationProvider);
}
创建WebSecurityConfiguration类
@Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
private Boolean debugEnabled;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
private ClassLoader beanClassLoader;
...省略...
@Bean(
name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null
&& !this.webSecurityConfigurers.isEmpty();
if(!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)
this.objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
return (Filter)this.webSecurity.build();
}
@Autowired(
required = false
)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object>
objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
//创建一个webSecurity对象
this.webSecurity = (WebSecurity)objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if(this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled.booleanValue());
}
//对所有配置类的实例进行排序
Collections.sort(webSecurityConfigurers, WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
//迭代所有配置类的实例 判断其order必须唯一
Iterator var5;
SecurityConfigurer config;
for(var5 = webSecurityConfigurers.iterator(); var5.hasNext(); previousConfig = config) {
config = (SecurityConfigurer)var5.next();
Integer order = Integer.valueOf(WebSecurityConfiguration.AnnotationAwareOrderComparator.lookupOrder(config));
if(previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
}
previousOrder = order;
}
//将所有的配置实例添加到创建的webSecutity对象中
var5 = webSecurityConfigurers.iterator();
while(var5.hasNext()) {
config = (SecurityConfigurer)var5.next();
this.webSecurity.apply(config);
}
//将webSercurityConfigures 实例放入该对象的webSecurityConfigurers属性中
this.webSecurityConfigurers = webSecurityConfigurers;
}
}
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers
该参数webSecurityConfigurers会将所有的配置实例放入该形参中
该方法中
1、创建webSecurity对象
2、主要检验了配置实例的order顺序(order唯一 否则会报错)
3、将所有的配置实例存放进入到webSecurity对象中,其中配置实例中含有我们自定义业务的权限控制配置信息
springSecurityFilterChain()方法
调用springSecurityFilterChain()方法,这个方法会判断我们上一个方法中有没有获取到webSecurityConfigurers,没有的话这边会创建WebSecurityConfigurerAdapter实例,并追加到websecurity中。接着调用websecurity的build方法。实际调用的是websecurity的父类AbstractSecurityBuilder的build方法 ,最终返回一个名称为springSecurityFilterChain的过滤器链。里面有众多Filter(springSecurity其实就是依靠很多的Filter来拦截url从而实现权限的控制的安全框架)
三、用户登录的验证和授权过程
1、用户一次完整的登录验证和授权,是一个请求经过 层层拦截器从而实现权限控制,整个web端配置为DelegatingFilterProxy(springSecurity的委托过滤其代理类 ),它并不实现真正的过滤,而是所有过滤器链的代理类,真正执行拦截处理的是由spring 容器管理的个个filter bean组成的filterChain.
调用实际的FilterChainProxy 的doFilterInternal()方法 去获取所有的拦截器并进行过滤处理如下是DelegatingFilterProxy的doFilter()方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Filter delegateToUse = this.delegate;
if(delegateToUse == null) {
Object var5 = this.delegateMonitor;
synchronized(this.delegateMonitor) {
delegateToUse = this.delegate;
if(delegateToUse == null) {
WebApplicationContext wac = this.findWebApplicationContext();
if(wac == null) {
throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = this.initDelegate(wac);
}
this.delegate = delegateToUse;
}
}
this.invokeDelegate(delegateToUse, request, response, filterChain);
}
调用实际的FilterChainProxy 的doFilter()方法 去获取所有的拦截器并进行过滤处理。
上一篇: SpringSecurity
推荐阅读
-
WEB中的权限管理(二)
-
乌合之众(大众心理研究)之二:群体的时代 博客分类: 管理
-
乌合之众(大众心理研究)之二:群体的时代 博客分类: 管理
-
如何解决MySQL的master-slave模式中ReplicationDriver的使用问题 博客分类: My SQL MySQLJDBCSpring配置管理REST
-
一个可能的列级权限控制方案讨论 博客分类: 技术 OracleAccess项目管理编程配置管理
-
web.xml 中的 servlet 和 servlet-mapping 标签 (转) 博客分类: sevrlet servlet
-
【转载】web.xml出现中
default 的作用 博客分类: jsp&servlet servlet -
web.xml中/ 与/*的区别;配置文件的匹配 博客分类: Servlet Servlet
-
系统开发中权限控制的重要性
-
关于web中的颜色表示方法,你知道多少?