Spring security 学习使用笔记
之前,我们的权限验证都混杂在业务逻辑中,用户在操作之前可能都要验证其是否拥有该项的操作权限,从而达到权限验证的目的,这种权限控制分布在业务的多个模块中,难以维护,认识spring security后用其与AOP(aspect oriented programming)结合很好解决了我们的应用程序的这类问题。我们使用aop将系统日志、性能监控和事务管理等功能从业务逻辑中分类出来,使用spring security将应用的安全逻辑分离出来,统一规划为系统业务逻辑。除此之外, Spring Security 提供了与很多通用企业认证系统的内置集成支持。所以, 对开发者来说,它通过很少的努力就能适应绝大多数的场景
在了解代码之前我们首先要先下载对应版本的spring和spring security包
通过http://static.springsource.org/spring-security/site/downloads.html现在所有版本的spring security,这里使用的是spring security3.1;然后现在http://www.springsource.org/download下载所有需要的spring版本,这里使用的是:spring 3.1;jdk用的是1.6,ide工具:Eclipse Java EE IDE for Web Developers.可以通过http://www.eclipse.org/webtools下载你所需要的版本。开发环境win7 ,测试环境linux。
现在让我们一起来认识一下spring security 吧。
spring security也就是被大家广为熟悉的acegi security,2007年底Acegi Security正式成为Spring Portfolio项目,并更名为Spring Security。Spring Security是一个能够为基于spring的企业应用系统提供描述性安全访问控制解决方案的安全框架。他提供了一组可以基于springIoC(依赖注入,也称控制反转)和AOP(面向切面编程)应用上下文中配置的Bean,充分利用了Spring功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
spring security 为企业应用提供了强大而灵活的安全服务,例如:
核心机制:认证和授权机制。
还有就是:web应用资源访问控制、业务方法访问控制、安全密码配置、单点登录sso、对openId的开发等等。
首先我们来了解一下关键概念和机制:
认证:是鉴别应用中的用户是否是其创建的用户。主要分为3类:
1、凭证为基础的认证:当你用账号和密码登录时就是提供了你的凭证来让应用认证你的用户身份,从而确认当前用户是否是合法用户。
2、两要素认证:当你去自动取款机取款时,你需要插入人行卡,确认后输入密码,这种方式和凭证的很类似,只是这里需要提供的是一个物理设备而不是单一的账号;这只是一个简单的两要素认证类中;类似的还有很多。
3、硬件认证:当你启动汽车、摩托车是需要插入钥匙然后打火启动,这就是一个硬件认证。
授权:通常涉及到两个方面,他们共同实现对安全系统的可访问行。
1、已认证的用户与一个或多个权限的关系。
2、分配权限给系统中需要安全控制的访问资源。
实际中我们对管理权限控制流程一般如下图:
我们可以看到,有一个名为访问决策管理器(access decision manager)的组件来负责决定一个安全实体是不是有适当的访问权限,判断基于安全实体具备的权限与被请求资源所要求资源的匹配情况。安全访问控制器对访问是否被允许的判断过程可能会很简单,就像查看安全实体所拥有的权限集合与被访问资源所要求的资源集合是不是有交集。
下面来介绍一下spring security的主要3个组件:
1、AbstractAuthenticationProcessingFilter:它在基于 web 的认证请求中使用。处理包含认证信息的请求,如认证信息可能是 form
POST提交的、 SSO信息或者其他用户提供的。创建一个部分完整的 Authentication 对象以在链中传递凭证信息。
2、AuthenticationManager:它用来校验用户的凭证信息,或者会抛出一个特定的异常(校验失败的情况)或者完整填充 Authentication对象,
将会包含了权限信息。
3、AuthenticationProvider:它为 AuthenticationManager 提供凭证校验。一些 AuthenticationProvider 的实现基于凭证
信息的存储,如数据库,来判定凭证信息是否可以被认可。
这里让我通过下面的流程图来细致的看一下这三个组件之间的关系:
通过上图可以很清晰了解到3各组件之间的关系。这里就不详细说明了,如果想更细致得了解,请查看官网文档和相关资料。
下面我们来创建spring security项目,在我们的使用中有4中方法
一是全部利用配置文件,将用户、权限、资源(url)硬编码在xml文件中
二是用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置
三是细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器,
并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置
并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置
四是修改spring security的源代码,主要是修改InvocationSecurityMetadataSourceService和UserDetailsService两个类。
前者是将配置文件或数据库中存储的资源(url)提取出来加工成为url和权限列表的Map供Security使用,后者提取用户名和权限组成一个完整的(UserDetails)User对象,该对象可以提供用户的详细信息供AuthentationManager进行认证与授权使用。 现在我们就从第一种方法开始验证
首先我们创建一个java project项目(没有安装myeclipse,所以不能直接穿件web project),然后收到创建几个web必须的文件,这里不做详细说明了;然后将我们所需的jar包添加到相比的WEB-INF中的lib中,这里主要是将spring的核心包及aop等必须包加入,让后将springsecurity的spring-security-core-3.1.0.RELEASE.jar(这是核心代码库)和spring-security-web-3.1.0.RELEASE.jar及annotation有关的,比如使用注解对方法进行安全访问控制,在下一篇中会用到的包,其中也包括两个实例(tutorial和contacts),并且两个实例中都包括了如何使用Spring 3.10的命名空间来配置Spring Security,无论你对spring3命名空间的使用是否了解将使我们的配置文件大大缩短,简化开发,提高生产效率。到此我们的spring security3的项目已搭建完成。
现在我们需要配置web.xml来启动spring和spring security,在web.xml中添加如下代码
<!-- Spring begin -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml,classpath:applicationContext-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring end -->
<!-- 权限 begin -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 权限 end -->
大家可能很想知道DelegatingFilterProxy 是怎样找到 Spring Security 配置的过滤器链的,如果观察仔细的同学会发现filter-name:springSecurityFilterChain这个过滤器的名字并不是随意配置的,实际上会跟根据这个名字把 Spring Security 织入到DelegatingFilterProxy 。除非明确配置,否则 DelegatingFilterProxy 会在 SpringWebApplicationContext中寻找同名的配置 bean(名字是在 filter-name 中指明的)。更多配置DelegatingFilterProxy 的细节可以在这个类对应的 Javadoc 中找到.
接下来就是要创建spring 的配置文件applicationContext.xml,这个就根据你的实际项目需要来配置,不过过spring security的第一种使用方法验证中暂未用到 这里就不多说了。
下面要创建的配置文件必然是applicationContext-security.xml,在这里面添加
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http auto-config='true'>
<intercept-url pattern="/**" access="ROLE_ADMIN" />
<intercept-url pattern="/user/**" access="ROLE_USER" />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="macro" password="macro123456" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="xiangcai" password="xc888" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
这可以说是spring security最简单的配置文件,不过却说明了3大主要组件之间的关系。
那么 auto-config下都发生什么事情呢?
在 Spring Security 3中,使用 auto-config 会自动提供以下三个认证相关的功能:
HTTP 基本认证
Form 登录认证
退出
具体是怎么认证的回头看一下之前提到3个主要组件之间的流程图,那里详细的介绍了这个http认证过程。
在让我们更仔细的看看在基于web 用户名和密码认证的请求下,这些类的处理过程:
创建一个主页index。jsp和在/user下创建一个profile.jsp,但你试图访问应用主页时系统会跳转到http://localhost:8080/securitytest/spring_security_login:
查看页面源代码
我们会发现form中的actionURL 的 spring_security_login 部 分 表 明 这 是 一 个 默 认 的 登 录 的 页 面 并 且 是 在
DefaultLoginPageGeneratingFilter 中命名的。 我们可以使用配置属性来修改这个页面的名字从而使得它对于我们应用来说是唯一的。
这里我们使用
<authentication-manager>
<authentication-provider>
<user-service>
<user name="macro" password="macro123456" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="xiangcai" password="xc888" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
添加了两个用户,可以使用这个两个用户登录验证权限了
这里我们的authentication-manager没有和任何实现类关联,说明security默认机制中为我们做了许多机械式的配置。但要知道authentication-manager中是可以配置一个或多个authentication-provider的。
DaoAuthenticationProvider 是 AuthenticationProvider 的 简 单 封 装 实现 并 委 托o.s.s.core.userdetails.UserDetailsService 接口的实现类进行处理。UserDetailsService 负责返回o.s.s.core.userdetails.UserDetails的一个实现类。
应用基本完成了,有些累了,呵呵休息一下,有时间在加以完善!
回来了,接着来。
上面提到在访问应用首页时spring security会使其自动跳转到其自带的登录页面,那么,我们就很难修改这个页面,那如何是用自己的登录页面呢?
其实spring security设计者以为我们想好了,只需要在applicationContext-security.xml中配置一下就好了,在http中添加代码如下:
<form-login login-page="/templates/login.jsp"
authentication-failure-url="/templates/login.jsp?error=true"
default-target-url="/editpwd" />
login-page中配置自定义登录页面的url;
authentication-failure-url中配置权限审核失败后默认跳转页面url;
default-target-url:配置登录成功后默认跳转页面;
登录成功,最后当然不能少了登出了
术语退出(Logout)指的是用户使其安全 session 实效的一种操作。一般来说,用户在退出后,将会被重定向到站点的非安全保护的界面。 让我们在站点的页头部分添加一个“Log Out”的链接,并再次访问站点以了解其如何实现功能的。
我们现在navigation中添加一个 ”log out“(退出)菜单:
<c:url value="/j_spring_security_logout" var="logoutUrl"/>
<li><a href="${logoutUrl}">Log Out</a></li>
默认退出url是:j_spring_security_logout
需要记住的一点是任何URL请求在被servlet处理之前,都会经过Spring Security的过滤器链。所以,/j_spring_security_logout 这个 URL 请求并非对应系统中的一个 JSP,也不必有一个真正的 JSP 或者Spring MVC的目标来对其进行处理。这种类型的 URL 通常被称为虚拟 URL。
请求/j_spring_security_logout 的 URL 被 o.s.s.web.authentication.logout.LogoutFilter 过滤器所拦截。在Spring Security 的众多默认过滤器中,LogoutFilter专门匹配这个虚拟 URL 并执行相应的操作。
所以要在security配置文件的http中添加代码:例如:
<http auto-config="true" use-expressions="true">
<logout invalidate-session="true"
logout-success-url="/"
logout-url="/j_spring_security_logout"/>
</http>
1、使得HTTP session 失效(如果 invalidate-session属性被设置为 true)
2、清除SecurityContex(真正使得用户退出) ;
3、将页面重定向至 logout-success-url指明的 URL。
通过下图让我们进一步深入了解一下退出流程。
最后说明一下,退出的ulr是可以自定义的,如果退出还需要做其他处理,可以配置自己的退出url。
到这里一个简单的spring security应用就完成了。
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关推荐
与卿画眉共浮生 2020-11-13
smalllove 2020-11-03
hellowordmonkey 2020-11-02
丽丽 2020-10-30
周太郎 2020-10-28
greensomnuss 2020-10-27
职业炮灰 2020-10-16
与卿画眉共浮生 2020-10-14
feinifi 2020-10-14
feinifi 2020-10-13
yangjinpingc 2020-10-09
davis 2020-09-29
RickyIT 2020-09-27
lisongchuang 2020-09-27
tangxiong0 2020-09-03
meleto 2020-08-17
幸运小侯子 2020-08-14
YangHuiLiang 2020-08-06