序:這裏主要對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自己的性質還在研究,不會哦