栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

Spring Security详解/基于配置信息的Spring Security使用/使用自定义登录页面/Spring Security使用数据库认证/Spring Security源码分析

Spring Security详解/基于配置信息的Spring Security使用/使用自定义登录页面/Spring Security使用数据库认证/Spring Security源码分析

一、Spring Security介绍

Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。
Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别是使用领先的J2EE解决方案——Spring框架开发的企业软件项目。人们使用Spring Security有很多种原因,不过通常吸引他们的是在J2EE Servlet规范或EJB规范中找不到典型企业应用场景的解决方案。 特别要指出的是他们不能在 WAR 或 EAR 级别进行移植。这样,如果你更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用系统进行重新配置安全。使用Spring Security 解决了这些问题,也为你提供很多有用的,完全可以指定的其他安全特性。 安全包括两个主要操作。

  • “认证”,是为用户建立一个他所声明的主体。主题一般式指用户,设备或可以在你系 统中执行动作的其他系统。
  • “授权”,指的是一个用户能否在你的应用中执行某个操作,在到达授权判断之前,身份的主题已经由 身份验证过程建立了。

这些概念是通用的,不是Spring Security特有的。在身份验证层面,Spring Security广泛支持各种身份验证模式,这些验证模型绝大多数都由第三方提供,或则正在开发的有关标准机构提供的,例如 Internet Engineering Task Force。作为补充,Spring Security 也提供了自己的一套验证功能。

Spring Security 目前支持认证一体化如下认证技术: HTTP BASIC authentication headers (一个基于IEFT RFC 的标准) HTTP Digest authentication headers (一个基于IEFT RFC 的标准) HTTP X.509 client certificate exchange(一个基于IEFT RFC 的标准) LDAP (一个非常常见的跨平台认证需要做法,特别是在大环境) Form-based authentication (提供简单用户接口的需求) OpenID authentication Computer Associates Siteminder JA-SIG Central Authentication Service (CAS,这是一个流行的开源单点登录系统) Transparent authentication context propagation for Remote Method Invocation and HttpInvoker (一个Spring远程调用协议)

二、Spring Security快速入门 (一)基于配置信息的Spring Security使用

基于配置信息的Spring Security使用,即将用户信息存放在配置信息中。

新建一个Maven项目:



pom.xml:




  4.0.0

  com.fox.springSecurityTest
  SpringSecurity_Study
  1.0-SNAPSHOT
  war

  SpringSecurity_Study Maven Webapp
  
  http://www.example.com

  
    5.0.2.RELEASE
    5.0.1.RELEASE
  
  
    
      org.springframework
      spring-core
      ${spring.version}
    
    
      org.springframework
      spring-web
      ${spring.version}
    
    
      org.springframework
      spring-webmvc
      ${spring.version}
    
    
      org.springframework
      spring-context-support
      ${spring.version}
    
    
      org.springframework
      spring-test
      ${spring.version}
    
    
      org.springframework
      spring-jdbc
      ${spring.version}
    
    
    
      org.springframework.security
      spring-security-web
      ${spring.security.version}
    
    
      org.springframework.security
      spring-security-config
      ${spring.security.version}
    
    
      javax.servlet
      javax.servlet-api
      3.1.0
      provided
    
  
  
    
      
      
        org.apache.maven.plugins
        maven-compiler-plugin
        3.2
        
          1.8
          1.8
          UTF-8
        
      
      
        org.apache.tomcat.maven
        tomcat7-maven-plugin
        
          
          8090
          
          /
        
      
    
  

web.xml:



  SpringSecurity314

  
    contextConfigLocation
    classpath:spring-security.xml
  
  
    org.springframework.web.context.ContextLoaderListener
  
  
    springSecurityFilterChain  
    org.springframework.web.filter.DelegatingFilterProxy
  
  
    springSecurityFilterChain
    
        User user = new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(), userInfo.getStatus() == 0 ? false : true, true, true, true, getAuthority(userInfo.getRoles()));
        return user;
    }
	//作用就是返回一个List集合,集合中装入的是角色
    public List getAuthority(List roles){
        List authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
        }
        return authorities;
    }
}

运行Tomcat:
输入错误的用户名密码:


输入数据库中的用户名密码:


点击注销,又跳回到登录页面:

如果将数据库users表用户mike的status改为0,那么mike将也不能登录。

三、Spring Security源码分析 (一)在web.xml文件中的配置

问题:为什么DelegatingFilterProxy的filter-name必须是springSecurityFilterChain?


    springSecurityFilterChain  
    org.springframework.web.filter.DelegatingFilterProxy


    springSecurityFilterChain
    /*

DelegatingFilterProxy并不是真正的Filter,在其initFilterBean方法中会从WebApplicationContext根据delegate来获取到。

protected void initFilterBean() throws ServletException { 
	synchronized (this.delegateMonitor) { 
		if (this.delegate == null) { 
			// If no target bean name specified, use filter name. 
			if (this.targetBeanName == null) { 
				this.targetBeanName = getFilterName(); 
			}
			// Fetch Spring root application context and initialize the delegate early, 
			// if possible. If the root application context will be started after this 
			// filter proxy, we'll have to resort to lazy initialization. 
			WebApplicationContext wac = findWebApplicationContext(); 
			if (wac != null) { 
				this.delegate = initDelegate(wac); 
			} 
		} 
	} 
}

在上这代码中this.targetBeanName=getFilterName()就是获取名称叫做springSecurityFilterChain。
通过在doFilter就去中我们会发现真正干活的其实是delegate这个Filter,而delegate其实就是FilterChainProxy。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { 
	// Lazily initialize the delegate if necessary. 
	Filter delegateToUse = this.delegate; 
	if (delegateToUse == null) { 
		synchronized (this.delegateMonitor) {
			delegateToUse = this.delegate; 
			if (delegateToUse == null) { 
				WebApplicationContext wac = findWebApplicationContext(); 
				if (wac == null) { 
					throw new IllegalStateException("No WebApplicationContext found: " + "no ContextLoaderListener or DispatcherServlet registered?"); 
				}
				delegateToUse = initDelegate(wac); 
			}
			this.delegate = delegateToUse; 
		} 
	}
	// Let the delegate perform the actual doFilter operation. 
	invokeDelegate(delegateToUse, request, response, filterChain); 
}

FilterChainProxy是spring在解析配置文件时装配到上下文中,并且beanName为springSecurityFilterChain,因此在web.xml中需要配置filter-name为springSecurityFilterChain。

(二)在spring-security.xml文件中的配置

在配置文件中我们主要使用标签来完成配置

 
 
 
 
 
 

 
	 
	 
	

http标签是自定义标签,我们可以在spring-security-config包中查看:

http://www.springframework.org/schema/security=org.springframework.security.config.SecurityName spaceHandler

继续查看SecurityNamespaceHandler类,在其init方法:

public void init() { 
	loadParsers(); 
}

在loadParsers()方法中,指定由HttpSecurityBeanDefinitionParser进行解析

parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());

在HttpSecurityBeanDefinitionParser完成具体解析的parse方法中:

registerFilterChainProxyIfNecessary(pc, pc.extractSource(element));

这里就是注册了名为springSecurityFilterChain的filterChainProxy类。
接下我们在看一下注册一系列Filter的地方createFilterChain,在这个方法中我们重点关注

AuthenticationConfigBuilder authBldr = new AuthenticationConfigBuilder(element, 
	forceAutoConfig, pc, httpBldr.getSessionCreationPolicy(), 
	httpBldr.getRequestCache(), authenticationManager, 
	httpBldr.getSessionStrategy(), portMapper, portResolver, 
	httpBldr.getCsrfLogoutHandler());

我们可以查看AuthenticationConfigBuilder创建代码:

public AuthenticationConfigBuilder(Element element, boolean forceAutoConfig, 
	ParserContext pc, SessionCreationPolicy sessionPolicy, 
	BeanReference requestCache, BeanReference authenticationManager, 
	BeanReference sessionStrategy, BeanReference portMapper, 
	BeanReference portResolver, BeanmetadataElement csrfLogoutHandler) { 
		this.httpElt = element; 
		this.pc = pc; this.requestCache = requestCache; 
		autoConfig = forceAutoConfig | "true".equals(element.getAttribute(ATT_AUTO_CONFIG)); 
		this.allowSessionCreation = sessionPolicy != SessionCreationPolicy.NEVER && sessionPolicy != SessionCreationPolicy.STATELESS; 
		this.portMapper = portMapper; 
		this.portResolver = portResolver; 
		this.csrfLogoutHandler = csrfLogoutHandler; 
		
		createAnonymousFilter(); 
		createRememberMeFilter(authenticationManager); 
		createBasicFilter(authenticationManager); 
		createFormLoginFilter(sessionStrategy, authenticationManager); 
		createOpenIDLoginFilter(sessionStrategy, authenticationManager); 
		createX509Filter(authenticationManager); 
		createJeeFilter(authenticationManager); 
		createLogoutFilter(); 
		createLoginPageFilterIfNeeded();
		createUserDetailsServiceFactory(); 
		createExceptionTranslationFilter(); 
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/326656.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号