進階-使用Spring Security3.2搭建LDAP認證受權和Remember-me(1)

回顧

在以前的一篇博客中,Tomcat認證受權與簡單的SSO  我在tomcat cluster上搭建了一個簡單的網站,並試驗了各類認證受權BA,FBA,以及tomcat自身build-in的SSO機制。但就像摘要裏面寫的內容同樣,tomcat自身的FBA並很差用。重複一遍FBA的缺點:html

  1. login的過程沒法被幹預。咱們沒法經過添加filter的形式進行干預。login徹底交給web容器處理,頁面也是有web容器負責展現。java

  2. 沒有login地址,用戶沒法bookmark一個Login頁面。直接訪問login.html是沒法提交form的。login只能在訪問受保護資源的時候纔會被觸發。web

所以,我必須尋找一個新的認證方案。ajax

認證方案的甄選

如下幾點是我須要考慮的:spring

  1. JAVA平臺。編程

  2. 克服了FBA的缺陷。json

  3. 簡單易用。tomcat

  4. 穩定,一直存在維護,且充滿活力。安全

  5. 能夠跟各類認證系統集成,好比CAS,OpenSSO, JAVASSO, Kerberos, SAML.session

  6. 易於擴展,好比remember me, oauth2.

Spring Security 3則是很好的選擇。另外不得不提一下SecurityFilter, SecurityFilter是一個很是老的,基於servlet filter設計的一個認證框架,很是的簡單易上手。惋惜它好像從2005年,就沒再更新了。 若是想本身寫一個認證框架,SecurityFilter是一個很好的模仿對象。它的source如今能夠在這裏下載: http://securityfilter.sourceforge.net

接下來,開始使用Spring Security 3來從新搭建咱們的網站。

代碼下載

本篇文章和下一篇文章所生成的代碼都可以在此下載:http://pan.baidu.com/s/1nthpuDN 

開發環境搭建

Spring使用maven管理本身的發佈。因此基於Spring的開發,最好使用maven,不然理清楚Spring控件之間的依賴關係都要花很大的功夫。我在附件裏面上傳了一個PPT,介紹maven的概念和使用,http://pan.baidu.com/s/1kauU 。

  1. 安裝eclipse maven插件。help->install new software->輸入http://download.eclipse.org/technology/m2e/releases。安裝插件。

  2. 建立一個」Maven Project「, 選擇下面的archetype:

  3. 命名group id與artifect id.

  4. 點擊finish之後,一個maven的web項目就建成了。請在java目錄下建立java包和類,在resources下面放置resources,而在webapp下面放置web頁面文件與配置信息。


  5. 接下來,咱們須要修改pom.xml,增長對Spring的依賴

    <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>3.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>3.2.0.RELEASE</version>
        </dependency>
        <dependency>
      	<groupId>org.springframework.security</groupId>
      	<artifactId>spring-security-ldap</artifactId>
      	<version>3.2.0.RELEASE</version>
      </dependency>
  6. 在eclipse中,右鍵點擊project firstWeb --->Maven--->Update project. 這樣把項目全部依賴的jar包都自動下載到項目中。

Spring Security 3介紹

在進行試驗開發以前,我得嘚吧嘚吧Spring Security 3. 只有文字,沒有代碼的文章,不是好手冊。只有代碼,沒有文字的博客,則不是能夠被容易看懂的文章。

Spring在古老的記憶中,只是一個框架,它具備IoC和AoP的特性。然而近幾年,它已經變成了一個平臺。IoC與AoP依然成爲它的一個子項目Spring Framework。在覈心項目之上,又建立了十幾個很是具備競爭力的項目,好比Spring MVC, Spring Security, 這些項目覆蓋了J2EE領域中最多見的應用領域,包含Mobile,數據訪問。

Spring的上手不是特別簡單,但一旦上手,則是很是的簡單。緣由就在於它的IoC(控制反轉,也稱DI,依賴注入)和AoP(面向切面編程)。由於這兩樣東西,打破了一個程序的常規邏輯,使的邏輯和代碼分散在各個角落。這讓咱們只能看到樹葉,卻看不到大樹。然而,Spring的項目中高度使用了DI和AoP。這讓咱們在使用Spring的時候更注重使用形式而忽略了原理。

另外,Spring是一個很潮的社團,JAVA的新特性老是能獲得大力應用。因而Java annotation在Spring中也普遍的用起來,這更加劇了代碼的支離破碎。這就是爲何Spring上手難的緣由。

Spring Security3做爲Spring下的一個子項目,它既能夠跟Spring其它項目集成起來一塊兒使用,也能夠單獨使用,兩種狀況下的配置是不同的。另外,Spring Security3的配置文件上,又能夠分兩種, 基於XML的配置,和基於JAVA配置。

基於XML的配置易於修改,配置集中。基於Java的配置易於建立,語法簡單。但不管它如何變化無窮,咱們都必須擦亮眼睛,看清它的實質。它跟SecurityFilter和Struts2同樣,都是基於Servlet Filter(springSecurityFilterChain)來對全部的URL進行攔截的,而後再根據本身的配置,對各個URL進行轉發。全部的config只是爲了讓咱們能簡單的聲明URL的攔截和轉發的邏輯。

說了這麼多,恐怕你們都腦子亂掉了。接下來,我將從一個空項目開始,一步一步的搭建個人網站。注,本實驗把Spring Security3.2單獨使用,使用javaconfig。之因此使用javaconfig,是由於網上有太多的XML配置,但卻沒有javaconfig的複雜實例,甚至連官方文檔都沒有詳細的解釋。要想了解和Spring MVC的整合,以及XML的配置方式,請參考官方文檔。

網站開發

以前一篇文章已經有一個應用sessiontest.如今我不打算再用它。我將從上面新建的maven項目firstWeb開始從新建立一個網站。網站仍是將部署在以前的tomcat集羣上,使用前面文章配置好的OpenLDAP作用戶存貯。OpenLDAP的搭建,請看以前的文章。

首先搭建沒有安全保護的網站。如圖所示:

在webapp下面,存在index.jsp用於默認頁面。ajax目錄下則是給API用的,未來使用BA認證。html目錄下則是瀏覽網頁,將使用FBA認證,登錄頁面爲login.jsp。index.jsp上有一個FORM將提交到submit.jsp.

index.jsp

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
  <head>
    <title>Your selections</title>
  </head>
  <body>
  <a href="${pageContext.request.contextPath }/html/login.jsp">login</a>
  <a href="${pageContext.request.contextPath }/html/logout">logout</a>
    <% 
    String selections = (String)session.getAttribute("selections");
    selections=selections==null?"":selections;
    %>
    <form action="${pageContext.request.contextPath }/html/submit.jsp" method="post">
      <p>What do you prefer?</p>
      <p><input type="checkbox" name="car" value="car" <%
        if(selections.indexOf("car")>-1) out.print("checked=\"checked\""); %> />Car</p>
      <p><input type="checkbox" name="bike" value="bike" <% 
        if(selections.indexOf("bike")>-1) out.print("checked=\"checked\""); %> />Bike</p>
      <p><input type="checkbox" name="train" value="train" <% 
        if(selections.indexOf("train")>-1) out.print("checked=\"checked\""); %> />Train</p>
      <p><input type="checkbox" name="plane" value="plane" <% 
        if(selections.indexOf("plane")>-1) out.print("checked=\"checked\""); %> />Plane</p>
        <input type="hidden" name="<c:out value="${_csrf.parameterName}"/>" value="<c:out value="${_csrf.token}"/>"/> 
      <input type="submit" value="Submit" />
    </form>
  </body>
</html>

submit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Successful</title>
</head>
<body>
<a href="${pageContext.request.contextPath }/index.jsp">Back</a>
<a href="${pageContext.request.contextPath }/html/logout">logout</a>
<%
  StringBuffer sb = new StringBuffer();
  if (null !=request.getParameter("car"))sb.append("car;");
  if (null !=request.getParameter("bike"))sb.append("bike;");
  if (null !=request.getParameter("train"))sb.append("train;");
  if (null !=request.getParameter("plane"))sb.append("plane;");

  session.setAttribute("selections", sb.toString());
%>
Successful, please go back to check.<br>

</body>
</html>

login.jsp

<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page pageEncoding="UTF-8" %>

<html>
  <head>
    <title>Login</title>
  </head>

  <body onload="document.f.username.focus();">
    <h1>Login</h1>
    <c:if test="${not empty param.login_error}">
      <font color="red">
        Your login attempt was not successful, try again.<br/><br/>
        Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>.
      </font>
    </c:if>

    <form name="f" action="${pageContext.request.contextPath }/html/login" method="POST">
      <table>
        <tr><td>User:</td><td><input type='text' name='username' value='<c:if test="${not empty param.login_error}">fbloggs</c:if>'/></td></tr>
        <tr><td>Password:</td><td><input type='password' name='password'></td></tr>
        <tr><td><input type="checkbox" name="remember-me"></td><td>Don't ask for my password for two weeks</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>
      <input type="hidden" name="<c:out value="${_csrf.parameterName}"/>" value="<c:out value="${_csrf.token}"/>"/> 
    </form>

  </body>
</html>

403.jsp

<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
<%@ page import="org.springframework.security.core.Authentication" %>

<html>
  <head>
    <title>Access Denied</title>
  </head>

<body>
<h1>Sorry, access is denied</h1>

<p>
<%= request.getAttribute("SPRING_SECURITY_403_EXCEPTION")%>
</p>
<p>
<%      Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null) { %>
        Authentication object as a String: <%= auth.toString() %><br /><br />
<%      } %>
</p>
</body>
</html>

forbidden.html

<html>
<body>
If you see this page, that means web security succeeds.
</body>
</html>

status.jsp

<%@ page pageEncoding="UTF-8" contentType="application/json;charset=UTF-8"%>
{}&&{user: "${pageContext.request.remoteUser}"}

建立以上代碼頁面之後,咱們能夠運行maven install來發布web包,而後將web包部署到一個tomcat上。能夠經過http://localhost:8080/firstWeb  來開始瀏覽全部的頁面。這時候,全部的頁面都是公開的,沒有任何保護。

接下來,咱們使用Spring Security 3來配置認證和受權。 首先假設咱們是用XML來配置的話,通常是通過如下幾個步驟:

  1. 在web.xml中註冊springSecurityFilterChain.

  2. 在web.xml中指定Spring Security所使用的XML配置文件路徑。

  3. 建立XML配置文件。下面給出了一個XML的簡單例子。其中使用的是個人OpenLDAP做爲認證和受權。

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:s="http://www.springframework.org/schema/security"
        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.xsd">
    
        <s:http>
            <s:intercept-url pattern="/**" access="ROLE_RED" />
    
            <s:form-login />
            <s:anonymous />
            <s:logout />
        </s:http>
    
        <s:authentication-manager>
        
        <s:authentication-provider ref='ldapAuthProvider' />
        </s:authentication-manager>
    
        <!-- Traditional Bean version of the same configuration -->
       <bean id="contextSource"
           class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
         <constructor-arg value="ldap://127.0.0.1:389/dc=mycompany,dc=com"/>
         <property name="userDn" value="cn=admin,dc=mycompany,dc=com"/>
         <property name="password" value="admin"/>
       </bean>
    
       <bean id="ldapAuthProvider"
           class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
         <constructor-arg>
           <bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
               <constructor-arg ref="contextSource"/>
               <property name="userDnPatterns"><list><value>uid={0},ou=people</value></list></property>
           </bean>
         </constructor-arg>
         <constructor-arg>
           <bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator">
               <constructor-arg ref="contextSource"/>
               <constructor-arg value="ou=groups"/>
               <property name="groupRoleAttribute" value="cn"/>
               <property name="groupSearchFilter" value="uniqueMember={0}"/>
           </bean>
         </constructor-arg>
       </bean>
    </beans>

由於本文主要是javaconfig,因此上面的xml只是一個例子,對今天的項目並無實際做用。但上面的xml能夠輕鬆的教導咱們如何生成javaconfig。在缺失大量javaconfig的文檔的狀況下,參考xml能夠指導咱們javaconfig所使用的類與方法。

文字超上限了,下面請看(2)

進階-使用Spring Security3.2搭建LDAP認證受權和Remember-me(2) 

相關文章
相關標籤/搜索