学习Acegi-认证(authentication) - 深蓝的天空下,有你有我... -...
来源:百度文库 编辑:神马文学网 时间:2024/04/29 10:14:40
最近两星期在学习acegi,过程中感谢JavaEye,SpringSide和在网上提供acegi学习心得的网友们。
为了加深自己的认识,准备写下一些DEMO,希望可以给准备学习acegi的同学一些帮助。
作为安全服务离不开认证和授权这两个主要组成部分。而这篇文章就是针对acegi的认证服务。
学习Acegi-认证(authentication)
代码环境基于:
JDK1.5
acegi1.0.3
spring2.0
IDE基于:
Eclipse3.2+MyEclipse5.0.1
面向人员:
熟悉Eclipse+MyEclipse开发但刚开始了解acegi的人员。如果你是高手请指出文章不足之处。
1.建立一个MyEclipse的WebProject,把下列jar文件拷贝到项目的WEB-INF/lib目录:
acegi-security-1.0.3.jar
spring2.0.jar
费话说一句(占些字数):这是因为代码运行需要这两个包的支持。
2.修改WEB-INF下的web.xml文件,内容如下:
xml version = " 1.0 " encoding = " UTF-8 " ?>
< web - app version = " 2.4 " xmlns = " http://java.sun.com/xml/ns/j2ee "
xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xsi:schemaLocation = " http://java.sun.com/xml/ns/j2ee
http: // java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
< display - name > acegi Example of liuyxit display - name >
< context - param >
< param - name > contextConfigLocation param - name >
< param - value >
classpath:spring / applicationContext.xml
param - value >
context - param >
< filter >
< filter - name > Acegi Filter Chain Proxy filter - name >
< filter - class >
org.acegisecurity.util.FilterToBeanProxy
filter - class >
< init - param >
< param - name > targetClass param - name >
< param - value >
org.acegisecurity.util.FilterChainProxy
param - value >
init - param >
filter >
< filter - mapping >
< filter - name > Acegi Filter Chain Proxy filter - name >
< url - pattern > /*
org.springframework.web.context.ContextLoaderListener
其中FilterChainProxy实现了filter接口,它主要是实例化FilterChainProxy,并把所有动作交由FilterChainProxy处理。这样简化了web.xml的配置,并且充分利用了Spring IOC管理Bean的优势。
3.在src目录右键新建一个resource folder,在下面再建立acegi和spring目录
在spring目录中创建applicationContext.xml文件,内容:
xml version = " 1.0 " encoding = " UTF-8 " ?>
< beans xmlns = " http://www.springframework.org/schema/beans "
xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xmlns:aop = " http://www.springframework.org/schema/aop "
xmlns:tx = " http://www.springframework.org/schema/tx "
xsi:schemaLocation = " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http: // www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http: // www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd "
default - autowire = " byName " default - lazy - init = " true " >
< bean id = " filterChainProxy " class = " org.acegisecurity.util.FilterChainProxy " >
< property name = " filterInvocationDefinitionSource " >
< value >
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/** =authenticationProcessingFilter,exceptionTranslationFilter
liuyxit=123,ROLE_SUPERVISOR
user1=user1,ROLE_USER
user2=user2,disabled,ROLE_USER
其中filterChainProxy就是由web.xml声明的filter(FilterToBeanProxy)的targetClass。它主要是装载filterInvocationDefinitionSource指定的filter类(例子中为authenticationProcessingFilter,exceptionTranslationFilter),并顺序调用它们的doFilter方法,进行安全服务处理。
而authenticationProcessingFilter是处理一个认证表单,登陆用的表单必须提交用户名和密码这两个参数给这个filter.由用户名和密码构造一个UsernamePasswordAuthenticationToken,将传给AuthenticationManager的authenticate方法进行认证处理。该filter默认处理filterProcessesUrl属性指定的URL,认证失败会转到authenticationFailureUrl,认证成功会转到defaultTargetUrl页面。
AuthenticationManager顾名思义认证管理器,它只有一个接口方法authenticate用于返回认证结果,他的实现类由多个AuthenticationProvider进行投票,决定认证是否通过。
daoAuthenticationProvider是检验用户录入的认证数据是否正确(说白了就是用户名和密码是否正确)
inMemoryDaoImpl是给daoAuthenticationProvider提供系统的用户资料。而资料的来源是从配置中装载到内存的。
当认证不通过时,AuthenticationManager的实现类AbstractAuthenticationManager会抛出AuthenticationException类型的异常。这时排在最后的exceptionTranslationFilter会捕获该异常,并转向authenticationEntryPoint。
4.在WebRoot下创建index.jsp(其实不要也没关系,主要是为了方便),直接转向用户资料显示页。内容如下
<% @ page language = " java " pageEncoding = " UTF-8 " %>
< html >
< head >
< META HTTP - EQUIV = " Refresh " CONTENT = " 0;URL=userinfo.jsp " >
head >
< body >
< p > Loading p >
body >
html >
5.在WebRoot下创建userinfo.jsp,用于显示当前登陆的用户信息。内容如下
<% @ page language = " java " pageEncoding = " UTF-8 " %>
<% @ page import = " org.acegisecurity.context.SecurityContextHolder " %>
<% @ page import = " org.acegisecurity.userdetails.* " %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + " :// "
+ request.getServerName() + " : " + request.getServerPort()
+ path + " / " ;
%>
< html >
< head >
< base href = " <%=basePath%> " >
< title > My JSP ‘ pass.jsp ‘ starting page title >
< meta http - equiv = " pragma " content = " no-cache " >
< meta http - equiv = " cache-control " content = " no-cache " >
< meta http - equiv = " expires " content = " 0 " >
< meta http - equiv = " keywords " content = " keyword1,keyword2,keyword3 " >
< meta http - equiv = " description " content = " This is my page " >
head >
< body >
当前用户:
<%
Object obj = SecurityContextHolder.getContext().getAuthentication();
if ( null != obj){
Object userDetail = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = "" ;
if (userDetail instanceof UserDetails) {
username = ((UserDetails) userDetail).getUsername();
} else {
username = userDetail.toString();
}
out.print(username);
out.print( "
注销 " );
} else {
out.print( " 当前没有有效的用户 " );
out.print( "
登陆 " );
}
%>
body >
html >
6.在WebRoot下创建acegilogin.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 >
< head >
< title > Login title >
head >
< body >
< h1 > Login h1 >
< P > Valid users:
< P >
< P > username < b > liuyxit b > , password < b > 123 b > (supervisor)
< P > username < b > user1 b > , password < b > user1 b > (normal user)
< p > username < b > user2 b > , password < b > user2 b > (user disabled)
< p >
<%
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 action = " j_acegi_security_check " method = " POST " >
< table >
< tr >< td > User: td >< td >< input type = ‘ text ‘ name = ‘ j_username ‘ value = ‘ <%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY) %> ‘ > td > tr >
< tr >< td > Password: td >< td >< input type = ‘ password ‘ name = ‘ j_password ‘ > td > tr >
< tr >< td >< input type = " checkbox " name = " _acegi_security_remember_me " > td >< td > 2周内自动登录 td > tr >
< tr >< td colspan = ‘ 2 ‘ >< input name = " submit " type = " submit " > td > tr >
< tr >< td colspan = ‘ 2 ‘ >< input name = " reset " type = " reset " > td > tr >
table >
form >
body >
html >
6,OK,发布项目,访问http://localhost:8080/acegiexample
这时index.jsp会自动转向userinfo.jsp,由于还没有用户登录,所以没有资料显示。按登陆链接进入登录页,登录成功后会看到显示用户名的页面(当然可以有更多的用户资料,但这仅仅是example),不成功时会在登录页提示信息。我们可以用user1和user2登陆,可以分别测试登录成功和失败的流程。
7.可以看到登录页上有自动登陆功能,而userinfo.jsp页有注销功能。但还是不起作用,好,现在我们马上首手加入这两个功能。看acegi可以方便到什么程度。在applicationContext.xml中加入如下红色部分:
xml version = " 1.0 " encoding = " UTF-8 " ?>
< beans xmlns = " http://www.springframework.org/schema/beans "
xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xmlns:aop = " http://www.springframework.org/schema/aop "
xmlns:tx = " http://www.springframework.org/schema/tx "
xsi:schemaLocation = " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http: // www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http: // www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd "
default - autowire = " byName " default - lazy - init = " true " >
< bean id = " filterChainProxy " class = " org.acegisecurity.util.FilterChainProxy " >
< property name = " filterInvocationDefinitionSource " >
< value >
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/** =authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,exceptionTranslationFilter
class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
ref="authenticationManager"/>
class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
liuyxit=123,ROLE_SUPERVISOR
user1=user1,ROLE_USER
user2=user2,disabled,ROLE_USER
另要注意:Acegi默认的自动登陆设定参数名为_acegi_security_remember_me,注销链接为/j_acegi_logout。
马上重启Tomcat测试看看^_^。
8.通常用户资料会放在数据库中,而不会放在配置文件,接着下面我们来再行修改一下。
首先创建要用到的用户表和权限表,并插入初始化数据:
CREATE TABLE USERS(
USERNAME VARCHAR( 50 ) NOT NULL PRIMARY KEY,
PASSWORD VARCHAR( 50 ) NOT NULL,
ENABLED BIT NOT NULL)
INSERT INTO USERS(username,password,enabled) values( ‘ liuyxit ‘ , ‘ 123 ‘ , ‘ 1 ‘ )
INSERT INTO USERS(username,password,enabled) values( ‘ user1 ‘ , ‘ user1 ‘ , ‘ 1 ‘ )
INSERT INTO USERS(username,password,enabled) values( ‘ user2 ‘ , ‘ user2 ‘ , ‘ 0 ‘ )
CREATE TABLE AUTHORITIES(
USERNAME VARCHAR( 50 ) NOT NULL,
AUTHORITY VARCHAR( 50 ) NOT NULL,
CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME)
);
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( ‘ liuyxit ‘ , ‘ ROLE_SUPERVISOR ‘ )
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( ‘ user1 ‘ , ‘ ROLE_USER ‘ )
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( ‘ user2 ‘ , ‘ ROLE_USER ‘ )
这里我用的是acegi默认的数据结构,可以改只要你指定JdbcDaoImpl的authoritiesByUsernameQuery和usersByUsernameQuery属性就可以了。另AUTHORITIES表也要一同加入,原因acegi获得userDetail时,也会读取这个表的内容,否则会抛“nested exception is java.sql.SQLException: 对象名 ‘authorities‘ 无效”这个异常。
修改applicationContext.xml,变成如下:
xml version="1.0" encoding="UTF-8" ?>
< beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop ="http://www.springframework.org/schema/aop"
xmlns:tx ="http://www.springframework.org/schema/tx"
xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
default-autowire ="byName" default-lazy-init ="true" >
< bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name ="driverClassName" >
< value > net.sourceforge.jtds.jdbc.Driver value >
property >
< property name ="url" >
< value > jdbc:jtds:sqlserver://localhost:1433/javauser value >
property >
< property name ="username" >
< value > sa value >
property >
< property name ="password" >
< value > javauser value >
property >
bean >
< bean id ="filterChainProxy" class ="org.acegisecurity.util.FilterChainProxy" >
< property name ="filterInvocationDefinitionSource" >
< value >
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,exceptionTranslationFilter
value >
property >
bean >
< bean id ="authenticationProcessingFilter" class ="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter" >
< property name ="authenticationManager" ref ="authenticationManager" />
< property name ="authenticationFailureUrl" value ="/acegilogin.jsp?login_error=1" />
< property name ="defaultTargetUrl" value ="/userinfo.jsp" />
< property name ="filterProcessesUrl" value ="/j_acegi_security_check" />
bean >
< bean id ="rememberMeProcessingFilter"
class ="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter" >
< property name ="authenticationManager"
ref ="authenticationManager" />
< property name ="rememberMeServices" ref ="rememberMeServices" />
bean >
< bean id ="rememberMeServices"
class ="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices" >
< property name ="userDetailsService" ref ="jdbcDaoImpl" />
< property name ="key" value ="javargb" />
bean >
< bean id ="rememberMeAuthenticationProvider"
class ="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider" >
< property name ="key" value ="javargb" />
bean >
< bean id ="logoutFilter" class ="org.acegisecurity.ui.logout.LogoutFilter" >
< constructor-arg value ="/acegilogin.jsp" />
< constructor-arg >
< list >
< ref bean ="rememberMeServices" />
< bean class ="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
list >
constructor-arg >
bean >
< bean id ="authenticationManager" class ="org.acegisecurity.providers.ProviderManager" >
< property name ="providers" >
< list >
< ref local ="daoAuthenticationProvider" />
< ref local ="rememberMeAuthenticationProvider" />
list >
property >
bean >
< bean id ="daoAuthenticationProvider" class ="org.acegisecurity.providers.dao.DaoAuthenticationProvider" >
< property name ="userDetailsService" ref ="jdbcDaoImpl" />
bean >
< bean id ="jdbcDaoImpl" class ="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl" >
< property name ="dataSource" >< ref bean ="dataSource" /> property >
bean >
< bean id ="exceptionTranslationFilter" class ="org.acegisecurity.ui.ExceptionTranslationFilter" >
< property name ="authenticationEntryPoint" >
< bean class ="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint" >
< property name ="loginFormUrl" value ="/acegilogin.jsp" />
< property name ="forceHttps" value ="false" />
bean >
property >
< property name ="accessDeniedHandler" >
< bean class ="org.acegisecurity.ui.AccessDeniedHandlerImpl" >
< property name ="errorPage" value ="/accessDenied.jsp" />
bean >
property >
bean >
beans >
这时userDetailsService是通过实现类jdbcDaoImpl从数据库获得用户资料来作认证比较。
OK,大功告成。
后记:很少写技术文章,除了要坚持之外,文笔和思路都很重要。感觉自己的写作水平太差了,希望大家指出不合理的地方。有时间我会再写后篇《学习Acegi-授权(authorization)》,感谢大家把拙文看完,TKS!
为了加深自己的认识,准备写下一些DEMO,希望可以给准备学习acegi的同学一些帮助。
作为安全服务离不开认证和授权这两个主要组成部分。而这篇文章就是针对acegi的认证服务。
学习Acegi-认证(authentication)
代码环境基于:
JDK1.5
acegi1.0.3
spring2.0
IDE基于:
Eclipse3.2+MyEclipse5.0.1
面向人员:
熟悉Eclipse+MyEclipse开发但刚开始了解acegi的人员。如果你是高手请指出文章不足之处。
1.建立一个MyEclipse的WebProject,把下列jar文件拷贝到项目的WEB-INF/lib目录:
acegi-security-1.0.3.jar
spring2.0.jar
费话说一句(占些字数):这是因为代码运行需要这两个包的支持。
2.修改WEB-INF下的web.xml文件,内容如下:
xml version = " 1.0 " encoding = " UTF-8 " ?>
< web - app version = " 2.4 " xmlns = " http://java.sun.com/xml/ns/j2ee "
xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xsi:schemaLocation = " http://java.sun.com/xml/ns/j2ee
http: // java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
< display - name > acegi Example of liuyxit display - name >
< context - param >
< param - name > contextConfigLocation param - name >
< param - value >
classpath:spring / applicationContext.xml
param - value >
context - param >
< filter >
< filter - name > Acegi Filter Chain Proxy filter - name >
< filter - class >
org.acegisecurity.util.FilterToBeanProxy
filter - class >
< init - param >
< param - name > targetClass param - name >
< param - value >
org.acegisecurity.util.FilterChainProxy
param - value >
init - param >
filter >
< filter - mapping >
< filter - name > Acegi Filter Chain Proxy filter - name >
< url - pattern > /*
org.springframework.web.context.ContextLoaderListener
其中FilterChainProxy实现了filter接口,它主要是实例化FilterChainProxy,并把所有动作交由FilterChainProxy处理。这样简化了web.xml的配置,并且充分利用了Spring IOC管理Bean的优势。
3.在src目录右键新建一个resource folder,在下面再建立acegi和spring目录
在spring目录中创建applicationContext.xml文件,内容:
xml version = " 1.0 " encoding = " UTF-8 " ?>
< beans xmlns = " http://www.springframework.org/schema/beans "
xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xmlns:aop = " http://www.springframework.org/schema/aop "
xmlns:tx = " http://www.springframework.org/schema/tx "
xsi:schemaLocation = " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http: // www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http: // www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd "
default - autowire = " byName " default - lazy - init = " true " >
< bean id = " filterChainProxy " class = " org.acegisecurity.util.FilterChainProxy " >
< property name = " filterInvocationDefinitionSource " >
< value >
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/** =authenticationProcessingFilter,exceptionTranslationFilter
liuyxit=123,ROLE_SUPERVISOR
user1=user1,ROLE_USER
user2=user2,disabled,ROLE_USER
其中filterChainProxy就是由web.xml声明的filter(FilterToBeanProxy)的targetClass。它主要是装载filterInvocationDefinitionSource指定的filter类(例子中为authenticationProcessingFilter,exceptionTranslationFilter),并顺序调用它们的doFilter方法,进行安全服务处理。
而authenticationProcessingFilter是处理一个认证表单,登陆用的表单必须提交用户名和密码这两个参数给这个filter.由用户名和密码构造一个UsernamePasswordAuthenticationToken,将传给AuthenticationManager的authenticate方法进行认证处理。该filter默认处理filterProcessesUrl属性指定的URL,认证失败会转到authenticationFailureUrl,认证成功会转到defaultTargetUrl页面。
AuthenticationManager顾名思义认证管理器,它只有一个接口方法authenticate用于返回认证结果,他的实现类由多个AuthenticationProvider进行投票,决定认证是否通过。
daoAuthenticationProvider是检验用户录入的认证数据是否正确(说白了就是用户名和密码是否正确)
inMemoryDaoImpl是给daoAuthenticationProvider提供系统的用户资料。而资料的来源是从配置中装载到内存的。
当认证不通过时,AuthenticationManager的实现类AbstractAuthenticationManager会抛出AuthenticationException类型的异常。这时排在最后的exceptionTranslationFilter会捕获该异常,并转向authenticationEntryPoint。
4.在WebRoot下创建index.jsp(其实不要也没关系,主要是为了方便),直接转向用户资料显示页。内容如下
<% @ page language = " java " pageEncoding = " UTF-8 " %>
< html >
< head >
< META HTTP - EQUIV = " Refresh " CONTENT = " 0;URL=userinfo.jsp " >
head >
< body >
< p > Loading p >
body >
html >
5.在WebRoot下创建userinfo.jsp,用于显示当前登陆的用户信息。内容如下
<% @ page language = " java " pageEncoding = " UTF-8 " %>
<% @ page import = " org.acegisecurity.context.SecurityContextHolder " %>
<% @ page import = " org.acegisecurity.userdetails.* " %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + " :// "
+ request.getServerName() + " : " + request.getServerPort()
+ path + " / " ;
%>
< html >
< head >
< base href = " <%=basePath%> " >
< title > My JSP ‘ pass.jsp ‘ starting page title >
< meta http - equiv = " pragma " content = " no-cache " >
< meta http - equiv = " cache-control " content = " no-cache " >
< meta http - equiv = " expires " content = " 0 " >
< meta http - equiv = " keywords " content = " keyword1,keyword2,keyword3 " >
< meta http - equiv = " description " content = " This is my page " >
head >
< body >
当前用户:
<%
Object obj = SecurityContextHolder.getContext().getAuthentication();
if ( null != obj){
Object userDetail = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = "" ;
if (userDetail instanceof UserDetails) {
username = ((UserDetails) userDetail).getUsername();
} else {
username = userDetail.toString();
}
out.print(username);
out.print( "
注销 " );
} else {
out.print( " 当前没有有效的用户 " );
out.print( "
登陆 " );
}
%>
body >
html >
6.在WebRoot下创建acegilogin.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 >
< head >
< title > Login title >
head >
< body >
< h1 > Login h1 >
< P > Valid users:
< P >
< P > username < b > liuyxit b > , password < b > 123 b > (supervisor)
< P > username < b > user1 b > , password < b > user1 b > (normal user)
< p > username < b > user2 b > , password < b > user2 b > (user disabled)
< p >
<%
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 action = " j_acegi_security_check " method = " POST " >
< table >
< tr >< td > User: td >< td >< input type = ‘ text ‘ name = ‘ j_username ‘ value = ‘ <%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY) %> ‘ > td > tr >
< tr >< td > Password: td >< td >< input type = ‘ password ‘ name = ‘ j_password ‘ > td > tr >
< tr >< td >< input type = " checkbox " name = " _acegi_security_remember_me " > td >< td > 2周内自动登录 td > tr >
< tr >< td colspan = ‘ 2 ‘ >< input name = " submit " type = " submit " > td > tr >
< tr >< td colspan = ‘ 2 ‘ >< input name = " reset " type = " reset " > td > tr >
table >
form >
body >
html >
6,OK,发布项目,访问http://localhost:8080/acegiexample
这时index.jsp会自动转向userinfo.jsp,由于还没有用户登录,所以没有资料显示。按登陆链接进入登录页,登录成功后会看到显示用户名的页面(当然可以有更多的用户资料,但这仅仅是example),不成功时会在登录页提示信息。我们可以用user1和user2登陆,可以分别测试登录成功和失败的流程。
7.可以看到登录页上有自动登陆功能,而userinfo.jsp页有注销功能。但还是不起作用,好,现在我们马上首手加入这两个功能。看acegi可以方便到什么程度。在applicationContext.xml中加入如下红色部分:
xml version = " 1.0 " encoding = " UTF-8 " ?>
< beans xmlns = " http://www.springframework.org/schema/beans "
xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xmlns:aop = " http://www.springframework.org/schema/aop "
xmlns:tx = " http://www.springframework.org/schema/tx "
xsi:schemaLocation = " http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http: // www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http: // www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd "
default - autowire = " byName " default - lazy - init = " true " >
< bean id = " filterChainProxy " class = " org.acegisecurity.util.FilterChainProxy " >
< property name = " filterInvocationDefinitionSource " >
< value >
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/** =authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,exceptionTranslationFilter
liuyxit=123,ROLE_SUPERVISOR
user1=user1,ROLE_USER
user2=user2,disabled,ROLE_USER
另要注意:Acegi默认的自动登陆设定参数名为_acegi_security_remember_me,注销链接为/j_acegi_logout。
马上重启Tomcat测试看看^_^。
8.通常用户资料会放在数据库中,而不会放在配置文件,接着下面我们来再行修改一下。
首先创建要用到的用户表和权限表,并插入初始化数据:
CREATE TABLE USERS(
USERNAME VARCHAR( 50 ) NOT NULL PRIMARY KEY,
PASSWORD VARCHAR( 50 ) NOT NULL,
ENABLED BIT NOT NULL)
INSERT INTO USERS(username,password,enabled) values( ‘ liuyxit ‘ , ‘ 123 ‘ , ‘ 1 ‘ )
INSERT INTO USERS(username,password,enabled) values( ‘ user1 ‘ , ‘ user1 ‘ , ‘ 1 ‘ )
INSERT INTO USERS(username,password,enabled) values( ‘ user2 ‘ , ‘ user2 ‘ , ‘ 0 ‘ )
CREATE TABLE AUTHORITIES(
USERNAME VARCHAR( 50 ) NOT NULL,
AUTHORITY VARCHAR( 50 ) NOT NULL,
CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME)
);
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( ‘ liuyxit ‘ , ‘ ROLE_SUPERVISOR ‘ )
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( ‘ user1 ‘ , ‘ ROLE_USER ‘ )
INSERT INTO AUTHORITIES(USERNAME,AUTHORITY) values( ‘ user2 ‘ , ‘ ROLE_USER ‘ )
这里我用的是acegi默认的数据结构,可以改只要你指定JdbcDaoImpl的authoritiesByUsernameQuery和usersByUsernameQuery属性就可以了。另AUTHORITIES表也要一同加入,原因acegi获得userDetail时,也会读取这个表的内容,否则会抛“nested exception is java.sql.SQLException: 对象名 ‘authorities‘ 无效”这个异常。
修改applicationContext.xml,变成如下:
xml version="1.0" encoding="UTF-8" ?>
< beans xmlns ="http://www.springframework.org/schema/beans"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop ="http://www.springframework.org/schema/aop"
xmlns:tx ="http://www.springframework.org/schema/tx"
xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
default-autowire ="byName" default-lazy-init ="true" >
< bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource" >
< property name ="driverClassName" >
< value > net.sourceforge.jtds.jdbc.Driver value >
property >
< property name ="url" >
< value > jdbc:jtds:sqlserver://localhost:1433/javauser value >
property >
< property name ="username" >
< value > sa value >
property >
< property name ="password" >
< value > javauser value >
property >
bean >
< bean id ="filterChainProxy" class ="org.acegisecurity.util.FilterChainProxy" >
< property name ="filterInvocationDefinitionSource" >
< value >
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=authenticationProcessingFilter,logoutFilter,rememberMeProcessingFilter,exceptionTranslationFilter
value >
property >
bean >
< bean id ="authenticationProcessingFilter" class ="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter" >
< property name ="authenticationManager" ref ="authenticationManager" />
< property name ="authenticationFailureUrl" value ="/acegilogin.jsp?login_error=1" />
< property name ="defaultTargetUrl" value ="/userinfo.jsp" />
< property name ="filterProcessesUrl" value ="/j_acegi_security_check" />
bean >
< bean id ="rememberMeProcessingFilter"
class ="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter" >
< property name ="authenticationManager"
ref ="authenticationManager" />
< property name ="rememberMeServices" ref ="rememberMeServices" />
bean >
< bean id ="rememberMeServices"
class ="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices" >
< property name ="userDetailsService" ref ="jdbcDaoImpl" />
< property name ="key" value ="javargb" />
bean >
< bean id ="rememberMeAuthenticationProvider"
class ="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider" >
< property name ="key" value ="javargb" />
bean >
< bean id ="logoutFilter" class ="org.acegisecurity.ui.logout.LogoutFilter" >
< constructor-arg value ="/acegilogin.jsp" />
< constructor-arg >
< list >
< ref bean ="rememberMeServices" />
< bean class ="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
list >
constructor-arg >
bean >
< bean id ="authenticationManager" class ="org.acegisecurity.providers.ProviderManager" >
< property name ="providers" >
< list >
< ref local ="daoAuthenticationProvider" />
< ref local ="rememberMeAuthenticationProvider" />
list >
property >
bean >
< bean id ="daoAuthenticationProvider" class ="org.acegisecurity.providers.dao.DaoAuthenticationProvider" >
< property name ="userDetailsService" ref ="jdbcDaoImpl" />
bean >
< bean id ="jdbcDaoImpl" class ="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl" >
< property name ="dataSource" >< ref bean ="dataSource" /> property >
bean >
< bean id ="exceptionTranslationFilter" class ="org.acegisecurity.ui.ExceptionTranslationFilter" >
< property name ="authenticationEntryPoint" >
< bean class ="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint" >
< property name ="loginFormUrl" value ="/acegilogin.jsp" />
< property name ="forceHttps" value ="false" />
bean >
property >
< property name ="accessDeniedHandler" >
< bean class ="org.acegisecurity.ui.AccessDeniedHandlerImpl" >
< property name ="errorPage" value ="/accessDenied.jsp" />
bean >
property >
bean >
beans >
这时userDetailsService是通过实现类jdbcDaoImpl从数据库获得用户资料来作认证比较。
OK,大功告成。
后记:很少写技术文章,除了要坚持之外,文笔和思路都很重要。感觉自己的写作水平太差了,希望大家指出不合理的地方。有时间我会再写后篇《学习Acegi-授权(authorization)》,感谢大家把拙文看完,TKS!
学习Acegi-认证(authentication) - 深蓝的天空下,有你有我... -...
学习Acegi-认证(authentication)
学习Acegi-认证(authentication)
你有你的孤傲,我有我的深蓝
你有你的孤傲,我有我的深蓝
你有你的孤傲,我有我的深蓝【诗词转载】
你有你的孤傲,我有我的深蓝。
你有你的孤傲,我有我的深蓝
【情感天空】红尘有你!
【情感天空】红尘有你......
缘分天空有你同行
~缘分天空有你同行~
亲爱的澄 有你 天空笑了
学习资料:你有银行卡,就必须要知道的东西!?/? 薄雾倾城:倾城生活,有你有我!
学习资料:气质的培养 ?/? 薄雾倾城:倾城生活,有你有我!
学习资料:气质的培养 ?/? 薄雾倾城:倾城生活,有你有我!
学习资料:保证早起的六个习惯?/? 薄雾倾城:倾城生活,有你有我!
学习资料:脱口而出的100个精典句子?/? 薄雾倾城:倾城生活,有你有我!
学习资料:用最短的时间了解一个人?/? 薄雾倾城:倾城生活,有你有我!
学习资料:当领导的秘诀?/? 薄雾倾城:倾城生活,有你有我!
学习资料:过目不忘的记忆秘诀?/? 薄雾倾城:倾城生活,有你有我!
有你,有我
有你有我
学习资料:遇事最有水平的处理方法?/? 薄雾倾城:倾城生活,有你有我!