用戶登陸權限管理LDAP兩種配置參考文檔(spring-security和shiro)

 

序:這裏主要對springmvc 項目中用spring-security和shiro兩種鏈接LDAP的配置作說明html

用來實現ldap對用戶登陸及權限的管理 java

一:spring security方式node

(1)配置web.xml和導jar包:這裏用maven 導入(spring-ldap-core  spring-ldap-core-tiger  spring-security-ldap  spring-security-core  spring-security-web spring-security-config  spring-security-taglibs,這些都是1.31版本的jar)
 可能有些包不用,可是我都加了 (禮多人不怪)
 
 
在web.xml里加入以下
<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>
(2).配置spring-security文件
<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="/testttt" access="ROLE_ADMIN" /> -->
<s:intercept-url pattern="/admin/**" access="ROLE_USER" /> <!—全部請求admin開頭的都必須是ROLE_USER角色的用戶 
<s:intercept-url pattern="/captcha-p_w_picpath"
access="IS_AUTHENTICATED_ANONYMOUSLY" /> <!—若請求captcha-p_w_picpath,則不作驗證 
<s:anonymous />
<!- 配置一個自定義的登陸攔截器,由於默認的登陸攔截器不能爲咱們處理驗證碼等其餘登陸問題-
<s:custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter" /> 
<!--訪問登陸攔截器 -->
<s:http-basic entry-point-ref="authenticationEntryPoint" />
        <!-- 單點登陸配置 -->
<s:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<s:session-management session-authentication-strategy-ref="sas" />
<!-- 沒有權限不夠角色時訪問某個資源 處理的配置 -->
<s:access-denied-handler ref="accessDeniedHandler"/>
</s:http>
<!-進行登陸認證配置 authenticationManager 比較重要-
<s:authentication-manager alias="authenticationManager">
<s:ldap-authentication-provider
group-search-filter="member={0}" group-search-base="ou=groups"
user-search-base="ou=people" user-search-filter="uid={0}" />
<s:authentication-provider ref='secondLdapProvider' />
</s:authentication-manager>
<!-- 401 密碼錯誤 403 沒有權限 404 頁面沒找到 413 上傳的文件或數據過大 -->
<!-- 此爲權限不夠角色,登陸失敗時異常攔截器 -->
<bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
<property name="accessDeniedHandler" ref="accessDeniedHandler" />
</bean>
<!-- 登陸頁面入口 -->
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/sign_in" />
</bean>
<!-- 在沒有權限不夠角色訪問此資源時跳轉入口 -->
<bean id="accessDeniedHandler"
class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<property name="errorPage" value="/authority.html" />
</bean>
<!-調用自定義登陸攔截器MySpecialAuthenticationFilter,並配置 authenticationManager登陸認證及其餘認證-
<bean id="authenticationFilter" class="com.zqgame.util.MySpecialAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<!-- 調用單點登陸認證配置 -->
<property name="sessionAuthenticationStrategy" ref="sas" />
<property name="filterProcessesUrl" value="/auth" /><!-- 調用處理登陸的action -->
<property name="authenticationSuccessHandler" ref="successHandler" /><!-- 
調用登陸認證成功後的處理 -->
<property name="authenticationFailureHandler" ref="simpleUrlAuthenticationFailureHandler" /><!-- 
調用登陸失敗後的處理配置 -->
</bean>
<!--登陸認證成功後的處理
<bean id="successHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/body/adminmain" />
</bean>
<!--登陸失敗後的處理配置
<bean id="simpleUrlAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login_error" />
</bean>
 
<!-- 單點登陸配置 begin -->
<bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<property name="sessionRegistry" ref="sessionRegistry" />
<property name="expiredUrl" value="/session-expired.html" />
</bean>
<bean id="sas"
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<property name="maximumSessions" value="1" />
</bean>
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
<!-- 單點登陸配置 end -->
<!-下面就是根據本身所要鏈接的ldap具體狀況來作ldap的自己配置了-
<bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg value="ldap://180.96.13.102:389/dc=zqgame,dc=com" />
</bean>
 
<bean id="secondLdapProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<constructor-arg>
<bean
class="org.springframework.security.ldap.authentication.BindAuthenticator">
<constructor-arg ref="contextSource" />
<property name="userSearch">
<bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value="ou=people" />
<constructor-arg index="1" value="(uid={0})" />
<constructor-arg index="2" ref="contextSource" />
</bean>
</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="groupSearchFilter" value="(member={0})" />
<property name="rolePrefix" value="ROLE_" />
<property name="searchSubtree" value="true" />
<property name="convertToUpperCase" value="true" />
</bean>
</constructor-arg>
</bean>
</beans>
 
(3) 自定義攔截器com.zqgame.util.MySpecialAuthenticationFilter
這個攔截器就是作ldap登陸認證的,裏面包括了一些用戶輸入信息正確性判斷和驗證碼判斷(全部不能登陸狀況都是異常捕獲)AuthenticationServiceException會根據上面的配置文件中登陸錯誤的配置而跳轉
 
package com.zqgame.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
public class MySpecialAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
public MySpecialAuthenticationFilter() {
super("/auth");//這個auth就是外面要訪問這個攔截器的入口
}
    public MySpecialAuthenticationFilter(String defaultFilterProcessesUrl) {
super("/auth");
}
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "j_username";
    public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "j_password";
    private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
    private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
   public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
HttpSession session = request.getSession();
String username = obtainUsername(request);
String password = obtainPassword(request);
String catchImage = request.getParameter("captcha");//驗證碼
//判斷用戶名登陸密碼是否爲空
       if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
session.setAttribute("loginError", "請輸入用戶名或者密碼!");
throw new AuthenticationServiceException("j_username or j_password is not null!"); //跳轉到login_error下
}
// 從session中得到驗證碼,與用戶輸入的驗證碼作比較
String sessionCaptcha = (String) session.getAttribute(Constant.CAPTCHA);
if (StringUtils.isEmpty(catchImage) || StringUtils.isEmpty(sessionCaptcha)) {
session.setAttribute("loginError", "驗證碼爲空!");
  throw new AuthenticationServiceException("the session captcha is not null!");//跳轉到login_error下
  }
session.removeAttribute(Constant.CAPTCHA);// 清空Sesion裏的驗證碼
         //驗證碼輸入校驗
        if (!sessionCaptcha.equalsIgnoreCase(catchImage)) {
        session.setAttribute("loginError", "驗證碼輸入錯誤!");
throw new AuthenticationServiceException("the captcha is error!");//跳轉到login_error下
}                
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
setDetails(request, authRequest);
Authentication authen = null;
      //執行ldap的登陸驗證
try {
 authen = this.getAuthenticationManager().authenticate(authRequest);
} catch (AuthenticationException failed) {
         session.setAttribute("loginError", "用戶名或密碼錯誤!");
  throw new AuthenticationServiceException("the captcha is error!");//跳轉到login_error
}
session.setAttribute("managerSession", username);
   return authen;
}
 
   
    protected String obtainPassword(HttpServletRequest request) {
        return request.getParameter(passwordParameter);
    }
 
   
    protected String obtainUsername(HttpServletRequest request) {
        return request.getParameter(usernameParameter);
    }
 
   
    protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
}
 
 
(4)登陸Action類
package com.zqgame.controllers.admin;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.zqgame.common.Constant;
import com.zqgame.models.SignIn;
import com.zqgame.services.UserService;
import com.zqgame.util.Digest;
/**
 * 後臺登陸控制器
 * @author User
*/
@Controller
public class SessionsController{
/**
* 進入登陸頁面
* @return
*/
@RequestMapping(value = "/sign_in", method = RequestMethod.GET)
public String newForm(Model model) {
return "admin/sessions/new";
}
 
/**
* 登陸錯誤
* @return
*/
@RequestMapping(value = "/login_error", method = RequestMethod.GET)
public String loginError(Model model) {
return "admin/sessions/new";
}
/**
* 退出登陸 logout() 銷燬會話 
* @param request
* @return
*/
@RequestMapping(value = "signout")
public void signOut(HttpServletRequest request, HttpServletResponse response) {
try {
SecurityContextLogoutHandler securityLogout = new SecurityContextLogoutHandler();
securityLogout.logout(request, response, null);
request.getRequestDispatcher(
"WEB-INF/views/admin/sessions/loginout.jsp").forward(
request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
(5)登陸jsp頁面form部分
<form action="/auth" id="loginForm" method="post"> //auth就是那個自定義攔截器的訪問路徑,而不是去action
<div class="box">
<c:if test="${!empty sessionScope.loginError}">
<fmt:message key='${sessionScope.loginError}' />
<c:remove var="loginError" scope="session" />//刪除session中存儲的錯誤提示
用戶:<input type="text" class="inp1" name="j_username" id="username" size="12" maxlength="50" value="${signIn.j_username}"/>
<br>
密碼:<input type="password" class="inp2" name="j_password" id="password"  size="12" maxlength="50"/>
<br>
驗證碼:<input type="text" name="captcha" id="captcha" class="login_input required" MaxLength="6" style="width:55px;text-transform:uppercase;"/>
<br>這個驗證碼具體怎麼生成的這裏不作說明
<input type="submit">登 錄</input>
</form>
上面就是整個LDAP與spring-security的配置了,固然這裏只是我本身的處理方式,可能還有不少很差的地方,但願拍磚
 
二.Shiro 方式
(1)配置web.xml和導包(shiro-core  shiro-web shiro-spring  cglib-nodep 版本1.2.0)
Web.xml里加入
<filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
</filter-mapping>
(2)Shiro配置文件(文檔裏有註釋,這個配置文件基本上不用改啥)
<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
 
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <property name="loginUrl" value="/sign_in"/> 
        <property name="successUrl" value="/body/adminmain"/>
<property name="filterChainDefinitions"><!—配置請求須要處理方式
<value>
                /sign_in = anon
                /admin/** = authc <!--admin的url所有要可以被驗證經過-->
                /sign_up = anon
                /captcha-p_w_picpath = anon
                /sessions/** = anon
</value>
</property>
</bean>
<bean id="sha512Matcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="${shiro.hashAlgorithmName}" />
<property name="storedCredentialsHexEncoded" value="${shiro.storedCredentialsHexEncoded}" />
<property name="hashIterations" value="${shiro.hashIterations}" />
</bean>
      <bean id="openldapRealm" class="org.apache.shiro.realm.ldap.JndiLdapRealm">
<!-配置登陸認證訪問ldap的樹域-
        <property name="userDnTemplate" value="cn={0},dc=zqgame,dc=com"/>
        <property name="contextFactory" ref="contextFactory" />
    </bean> 
<!-配置ldap路徑及配置一個默認的用戶和密碼-
     <bean id="contextFactory" class="org.apache.shiro.realm.ldap.JndiLdapContextFactory">
        <property name="url" value="ldap://180.96.13.102:389/??sub"/>
        <property name="systemUsername" value="ldapuser"/>
        <property name="systemPassword" value="zqgame.com"/>
    </bean> 
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="openldapRealm" />
        <property name="sessionMode" value="native"/>
    </bean>
   <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
</beans>
(3)登陸action(這裏action不用那麼麻煩,因此這裏就把登陸的action和退出的action寫上吧)
/*執行登陸*/
public String create(@Valid SignIn signIn, BindingResult result, HttpSession session, Model model) {
       if (result.hasErrors()) {
        model.addAttribute("loginError", "請輸入內容!");
        model.addAttribute("signIn", signIn);
            return "admin/sessions/new";
        }
    //從session中得到驗證碼
    String sessionCaptcha = (String) session.getAttribute(Constant.CAPTCHA);
    if(StringUtils.isEmpty(sessionCaptcha)) {
    model.addAttribute("loginError", "session裏的驗證碼爲空!");
    return "admin/sessions/new";
    }
    session.removeAttribute(Constant.CAPTCHA);//清空驗證碼
        if(!sessionCaptcha.equalsIgnoreCase(signIn.getCaptcha())) {
        model.addAttribute("loginError", "驗證碼輸入錯誤!");
        return "admin/sessions/new";
        } 
       /*shiro執行ldap登陸認證*/
        UsernamePasswordToken token = new UsernamePasswordToken(signIn.getUsername(), signIn.getPassword());
        token.setRememberMe(true);
        Subject currentUser = SecurityUtils.getSubject();
        try {
            currentUser.login(token);
            session.setAttribute(Constant.MANAGER_SESSION, signIn.getUsername());
        }catch (Exception ice) {
             result.reject("mismatch.signIn.password"); 
            //password didn't match, try again?
        } 
        if (currentUser.isAuthenticated()) {//登陸成功進入主頁
            return "redirect:/body/adminmain";
        }
        model.addAttribute("loginError", "您輸入的用戶名或密碼錯誤!");
        return "admin/sessions/new";
    }
/**
* 退出登陸
* logout() 銷燬回話
* @return
*/
@RequestMapping(value = "signout", method = RequestMethod.GET)
 public void signOut(HttpServletRequest request, HttpServletResponse response) {
    SecurityUtils.getSubject().logout();
    try {
request.getRequestDispatcher("WEB-INF/views/admin/sessions/loginout.jsp").forward(request, response);
} catch (ServletException e) {
          e.printStackTrace();
} catch (IOException e) {
 e.printStackTrace();
}
}
到此兩種方式均可以使用了,至於那個配置文件,能夠把他放到web.xml里加載就行,就跟加載spring的文件同樣就行
另:ldap自己的性質還在研究,不會哦
相關文章
相關標籤/搜索