acegi security實踐教程—form認證

  
  上篇博客給大家介紹了basic認證,同時也帶領大家debug了一下源碼,所以流程想必大家都已經瞭解了,那麼現在只剩下各種認證的配置了。

  具體步驟如下:

  開發環境:

  MyEclispe10.7.1+tomcat6.0.37+acegi1.0.5+spring2.0
  項目目錄如下:  其中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.因爲訪問受保護資源,沒有登錄,則轉到登陸頁面
   
  
  3.輸入無權限用戶,test/1,因爲無權限,則轉向accessDefined頁面
  
 
4.輸入有權限用戶,lisi/1,則成功轉向到userinfo.jsp
  sendRedirect(request, response, targetUrl);
 
  OK,運行成功了,這篇博客實踐源碼:
  ps:關閉瀏覽器,重新再打開瀏覽器,運行http://localhost:8080/acegitest2/userinfo.jsp,測試一下會出現啥現象?再換個瀏覽器比如谷歌,運行url會出現啥現象?這個現象的原因能猜到嗎?


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章