上篇博客给大家介绍了basic认证,同时也带领大家debug了一下源码,所以流程想必大家都已经了解了,那么现在只剩下各种认证的配置了。
具体步骤如下:
开发环境:
MyEclispe10.7.1+tomcat6.0.37+acegi1.0.5+spring2.0
项目目录如下: 其中readme主要用来记录本次验证目的
项目目录如下: 其中readme主要用来记录本次验证目的
配置文件
web.xml:
<?xml version="1.0" encoding= "UTF-8"?>
<web-app xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns= "http://java.sun.com/xml/ns/javaee" xmlns:web= "http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version= "2.5">
< display-name></display-name >
<!-- spring 配置文件 -->
< context-param>
<param-name >contextConfigLocation </param-name >
<param-value >
classpath:config/spring/spring-acegi.xml
</param-value >
</ context-param>
<!-- acegi对页面校验控制 -->
< filter>
<filter-name >AcegiFilterChainProxy </filter-name >
<filter-class >
org.acegisecurity.util.FilterToBeanProxy
</filter-class >
<init-param >
<param-name >targetBean </param-name >
<param-value >filterChainProxy </param-value >
</init-param >
</ filter>
< filter-mapping>
<filter-name >AcegiFilterChainProxy </filter-name >
<url-pattern >/j_acegi_security_check </url-pattern >
</ filter-mapping>
< filter-mapping>
<filter-name >AcegiFilterChainProxy </filter-name >
<url-pattern >/j_acegi_logout </url-pattern >
</ filter-mapping>
< filter-mapping>
<filter-name >AcegiFilterChainProxy </filter-name >
<url-pattern >*.do </url-pattern >
</ filter-mapping>
< filter-mapping>
<filter-name >AcegiFilterChainProxy </filter-name >
<url-pattern >*.jsp </url-pattern >
</ filter-mapping>
< welcome-file-list>
<welcome-file >index.jsp </welcome-file >
</ welcome-file-list>
<!-- spring配置 -->
< listener>
<listener-class >
org.springframework.web.context.ContextLoaderListener
</listener-class >
</ listener>
</web-app>
acegi配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns= "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-2.0.xsd" >
<!-- 通过过滤连形式,acegi提供很多filter,其中过滤器执行也有一定的顺序 ,同事支持正则和ant匹配-->
<bean id ="filterChainProxy" class= "org.acegisecurity.util.FilterChainProxy" >
<property name ="filterInvocationDefinitionSource">
<value >
PATTERN_TYPE_APACHE_ANT
/**=authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value >
</property >
</bean >
<!-- 表单认证处理filter -->
<bean id ="authenticationProcessingFilter" class= "org.acegisecurity.ui.webapp.AuthenticationProcessingFilter" >
<!-- 认证管理器,然后委托给Provides -->
<property name ="authenticationManager" ref= "authenticationManager"/>
<!-- 认证失败后转向的url,包含出错信息的的登陆页面 -->
<property name ="authenticationFailureUrl" value= "/login.jsp?login_error=1"/>
<!-- 登陆成功后转向的url -->
<property name ="defaultTargetUrl" value= "/userinfo.jsp"/>
<!-- 登陆的url,这个是默认的acegi自带的 -->
<property name ="filterProcessesUrl" value= "/j_acegi_security_check"/>
</bean >
<bean id ="authenticationManager"
class= "org.acegisecurity.providers.ProviderManager" >
<property name ="providers">
<list >
<ref local ="daoAuthenticationProvider" />
</list >
</property >
</bean >
<!-- 从数据库中读取用户信息验证身份 -->
<bean id ="daoAuthenticationProvider"
class= "org.acegisecurity.providers.dao.DaoAuthenticationProvider" >
<property name ="userDetailsService" ref= "inMemDaoImpl" />
</bean >
<!-- 基于内存实现方式-->
<bean id ="inMemDaoImpl"
class= "org.acegisecurity.userdetails.memory.InMemoryDaoImpl" >
<property name ="userMap">
<value >
test=1,ROLE_USER
lisi=1,ROLE_SUPERVISOR
zhangsan=1,ROLE_SUPERVISOR,disabled
</value >
</property >
</bean >
<!-- exception filter -->
<bean id ="exceptionTranslationFilter" class= "org.acegisecurity.ui.ExceptionTranslationFilter" >
<!-- 尚未登录, 进入非法(未认证不可访问)区域 -->
<property name ="authenticationEntryPoint">
<bean class= "org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint" >
<property name ="loginFormUrl" value= "/login.jsp"/> <!--若没登陆,则转向 用户登陆页面 -->
<property name ="forceHttps" value="false"/> <!-- 是否强制使用https -->
</bean >
</property >
<!-- 登录后, 进入非授权区域 -->
<property name ="accessDeniedHandler">
<bean class= "org.acegisecurity.ui.AccessDeniedHandlerImpl" >
<property name ="errorPage" value= "/accessDenied.jsp"/> <!-- 进入无权限页面 ,根据需求写相应的信息-->
</bean >
</property >
</bean >
<bean id ="filterInvocationInterceptor"
class= "org.acegisecurity.intercept.web.FilterSecurityInterceptor" >
<property name ="authenticationManager" ref= "authenticationManager" />
<property name ="accessDecisionManager" ref= "httpRequestAccessDecisionManager" />
<property name ="objectDefinitionSource">
<value ><![CDATA[
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/userinfo.jsp=ROLE_SUPERVISOR
]]></value>
</property >
</bean >
<bean id ="httpRequestAccessDecisionManager"
class= "org.acegisecurity.vote.AffirmativeBased" >
<property name ="decisionVoters">
<list >
<bean class= "org.acegisecurity.vote.RoleVoter" />
</list >
</property >
</bean >
</beans>
讲解如下:
在
filterInvocationInterceptor配置了受保护的资源,访问userinfo.jsp则需要
ROLE_SUPERVISOR权限。而其他的资源则不需要保护。
表单
authenticationProcessingFilter认证,也是依靠认证管理器,并委托给Provider来实现。
<
bean
id
=
"authenticationProcessingFilter"
class
=
"org.acegisecurity.ui.webapp.AuthenticationProcessingFilter"
>
<!-- 认证管理器,然后委托给Provides -->
<
property
name
=
"authenticationManager"
ref
=
"authenticationManager"
/>
<!-- 认证失败后转向的url,包含出错信息的的登陆页面 -->
<
property
name
=
"authenticationFailureUrl"
value
=
"/login.jsp?login_error=1"
/>
<!-- 登陆成功后转向的url -->
<
property
name
=
"defaultTargetUrl"
value
=
"/userinfo.jsp"
/>
<!-- 登陆的url,这个是默认的acegi自带的 -->
<
property
name
=
"filterProcessesUrl"
value
=
"/j_acegi_security_check"
/>
</
bean
>
其中的exception异常fiter,若没登陆,则转向登陆页面;若登陆了却访问了无权限资源,则转向accessDefined页面。
页面如下:
userinfo.jsp:显示用户信息
因为
SecurityContextHolder容器中存放securitycontext,其中securitycontext存放
Authentication对象。实际上
Authentication和
UserDetails很相似,只不过从后台取出来
UserDetails转换到
Authentication对象,存放到securitycontext
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import= "org.acegisecurity.context.SecurityContextHolder" %>
<%@ page import ="org.acegisecurity.userdetails.*"%>
<html>
<head>
<meta http-equiv= "Content-Type" content ="text/html; charset=UTF-8">
<title> 当前用户的具体信息 </title >
</head>
<body>
当前用户:
<%
Object obj = SecurityContextHolder.getContext().getAuthentication();
if ( null != obj){
Object userDetail = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = "";
String pwd= "";
if (userDetail instanceof UserDetails) {
username = ((UserDetails) userDetail).getUsername();
pwd = ((UserDetails) userDetail).getPassword();
} else {
username = userDetail.toString();
}
out.print(username+ ",密码:"+pwd);
}
%>
</body>
</html>
登陆页:login.jsp:
<%@ page language ="java" pageEncoding="UTF-8"%>
<%@ page import ="org.acegisecurity.ui.AbstractProcessingFilter" %>
<%@ page import= "org.acegisecurity.ui.webapp.AuthenticationProcessingFilter" %>
<%@ page import ="org.acegisecurity.AuthenticationException" %>
<html>
<body >
<%
String strError = request.getParameter( "login_error");
if (null != strError){
%>
<font color ="red">
你的登陆失败,请重试。 <BR ><BR >
原因: <%= ((AuthenticationException) session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
</font >
<%
}//end if
%>
< FORM METHOD= POST ACTION ="j_acegi_security_check">
< table>
<tr >
<td >用户名: </td >
<td ><input NAME ="j_username" type= "text" title ="用户名" /></td>
</tr >
<tr >
<td > 密码: </td >
<td ><input name ="j_password" type= "text" title = "密码"/></td >
</tr >
<tr >
<td > </td >
<td > <input type ="submit" value="登陆"/></ td></ tr>
</ table>
</FORM >
</ body>
其中注意:用户名和密码的name必须是j_username和j_password,以及action必须是j_acegi_security_check,这是acegi规则。
测试如下:
1.第一次运行userinfo.jsp
http://localhost:8080/acegitest2/userinfo.jsp
2.因为访问受保护资源,没有登录,则转到登陆页面