要学习spring security 我个人的学习步骤是首先运行一个demo,让自己有个感性认识,上一篇文章已经介绍过了,在此就不介绍了。

然后分析demo工作包括哪些包,每个包什么作用,然后分析原理和验证流程,最后详细研究配置文件等内容。

下面就是对源码分析的过程。

spring security 包内容:

Core-spring-security-core.jar

包含了核心认证和权限控制类和接口, 提供核心的程序支持和最基本的API。是使用Spring Security所必须使用的。支持单独运行的应用, 提供远程客户端,方法(服务层)的安全和JDBC用户验证。包含顶级包:

  • org.springframework.security.core

  • org.springframework.security.access

  • org.springframework.security.authentication

  • org.springframework.security.provisioning

  • org.springframework.security.remoting

Web - spring-security-web.jar

包含过滤器和对应的web安全架构代码。在需要任何依赖servlet API的地方你将需要它。如果你需要Spring Security Web认证服务和基于URL的权限控制,请使用它。 他的主包是org.springframework.security.web

Config - spring-security-config.jar

包含安全命名控制解析代码(因此我们不能直接把它用在你的应用中)。 如果使用了Spring Security XML命名控制来进行配置的时候需要使用。它的主包是org.springframework.security.config

LDAP - spring-security-ldap.jar

LDAP认证和实现代码,如果你需要使用LDAP认证或管理LDAP用户实体就是必须的。 它的顶级包是org.springframework.security.ldap

ACL - spring-security-acl.jar

处理领域对象ACL实现。用来提供安全特定的领域对象实例,在你的应用中。它的 顶级包是org.springframework.security.acls

CAS - spring-security-cas-client.jar

Spring Security的CAs客户端集成。如果你希望使用Spring Security web认证 整合一个CAS单点登录服务器。它的顶级包是 org.springframework.security.cas

OpenID - spring-security-openid.jar

OpenID web认证支持。用来认证用户,通过一个外部的OpenID服务。 org.springframework.security.openid。需要OpenID4Java。

crypto spring-security-crypto-3.1.0.RELEASE.jar

加密相关的包,它的顶级包是org.springframework.security.crypto

remoting spring-security-remoting-3.1.0.RELEASE.jar

远程客户端相关的包,主要包括dns、rmi、httpinvoker。它的顶级包是org.springframework.security.remoting

taglibs spring-security-taglibs-3.1.0.RELEASE.jar
web标签相关的包,可以用在jsp或者模板中。它的顶级包是org.springframework.security.taglibs

demo说明

根据官方文档spring-security-samples-tutorial-3.1.0.RELEASE.war是进行spring security的最基础的文档,于是就对这个工程进行了分析。引入了工程后,发现代码确实很少,jsp也很少就6个非常简单的jsp,然后通过tomcat运行,效果也很简单。

运行后发现一个很奇怪的现象就是找不到登录页,下图就是默认的home页面。

 

点击Secure page后会进入登录页面,但是这个页面在代码里面是找不到的,为了这个问题,我研究了好一会才发现登录页面的位置。

登录页面位于:org.springframework.security.web.authentication.ui包的DefaultLoginPageGeneratingFilter.java类中。
由DefaultLoginPageGeneratingFilter过滤器动态生成的一个页面。
 
这时候我想到了一个问题,就是为什么,home页面没有让登录,点击Secure page页面让登录呢?后来找到了答案。
在web登录的所有资源都是是否需要权限验证是放在配置文件applicationContext-security.xml中的。

<http use-expressions="true">

<!--下面两句表示在访问下面配置的资源的时候需要身份验证,如果没有身份验证跳转到登录页面-->
<intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')"/>
<intercept-url pattern="/secure/**" access="isAuthenticated()" />
<intercept-url pattern="/**" access="permitAll" />

<!--下面一句表示登录页面的配置选项,默认登录页就是上面由DefaultLoginPageGeneratingFilter生成的页面

默认跳转地址为/j_spring_security_check-->
<form-login />
<logout logout-success-url="/loggedout.jsp" delete-cookies="JSESSIONID"/>
<remember-me />
<session-management invalid-session-url="/timeout.jsp">
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>

</http>
 

isAuthenticated()定义的位置如下:

spring-security-core.jar中定义的接口

public interface Authentication extends Principal, Serializable {

Collection<GrantedAuthority> getAuthorities();

Object getCredentials();

Object getDetails();

Object getPrincipal();

boolean isAuthenticated();

void setAuthenticated(boolean isAuthenticated)throws IllegalArgumentException;

}

 

登录页面配置例子:
<form-login login-page="/login.jsp"default-target-url="/index.jsp" always-use-default-target="true" authentication-failure-url="/login.jsp?error=1" />
备注:在自定义的登录页面中用户名的名字为j_username,密码为j_password,记住密码为_spring_security_remember_me,这些内容都是写死的,写错了没有办法进行验证。
 
默认的验证代码为:
在包org.springframework.security.web.authentication,UsernamePasswordAuthenticationFilter过滤器中
关键代码为:
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//注意这里只能用post提交。
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}

String username = obtainUsername(request);
String password = obtainPassword(request);

if (username == null) {
username = "";
}

if (password == null) {
password = "";
}

username = username.trim();

UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

// Place the last username attempted into HttpSession for views
HttpSession session = request.getSession(false);

if (session != null || getAllowSessionCreation()) {
request.getSession().setAttribute(SPRING_SECURITY_LAST_USERNAME_KEY, TextEscapeUtils.escapeEntities(username));
}

// Allow subclasses to set the "details" property
setDetails(request, authRequest);

return this.getAuthenticationManager().authenticate(authRequest);
}

用户信息的配置是放在配置文件applicationContext-security.xml中的,关键配置项为:
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder"/>
<user-service>
<user name="rod" password="4efe081594ce25ee4efd9f7067f7f678a347bccf2de201f3adf2a3eb544850b465b4e51cdc3fcdde" authorities="supervisor, user, teller" />
<user name="dianne" password="957ea522524a41cbfb649a3e293d56268f840fd5b661b499b07858bc020d6d223f912e3ab303b00f" authorities="user,teller" />
<user name="scott" password="fb1f9e48058d30dc21c35ab4cf895e2a80f2f03fac549b51be637196dfb6b2b7276a89c65e38b7a1" authorities="user" />
<user name="peter" password="e175750688deee19d7179d444bfaf92129f4eea8b4503d83eb8f92a7dd9cda5fbae73638c913e420" authorities="user" />
</user-service>
</authentication-provider>
</authentication-manager>
上面就是对demo的基本研究。
最后想说的就是框架其实只是用来快速开发用的,很多框架基本上都封装了实现的细节,我们只知道怎么用是远远不够的,那样干的只是体力活,更多的我们应该去知道它为什么这么用,怎么实现的,然后我们可以不用框架,也可以写出很好的代码。其实说白了,我们最需要掌握的就是解决问题的能里,能不是去跟别人说我会用什么什么框架之类的!