package com.work.qxgl.login;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.config.DefaultSettings;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.work.core.QxglConstants;
import com.work.core.spring.MyBeanUtil;
import com.work.qxgl.model.QxglRole;
import com.work.qxgl.usermodel.UserModelServiceDao;
public class AuthorizationInterceptor extends AbstractInterceptor {
/**
*
*/
private static final long serialVersionUID = 4949812834762901805L;
private static Log log = LogFactory.getLog(AuthorizationInterceptor.class);
@Override
public String intercept(ActionInvocation invocation) throws Exception {
// 取得請求的Action名
String name = invocation.getInvocationContext().getName(); // action
// 的名稱,在xml中配置的
String namespace = invocation.getProxy().getNamespace(); // 獲取到namespace,還能夠獲取到要執(zhí)行的方法,class等
if ((namespace != null) && (namespace.trim().length() > 0)) {
if ("/".equals(namespace.trim())) {
// 說明是根路徑,不需要再增加反斜杠了。
} else {
namespace += "/";
}
}
String URL = namespace + invocation.getProxy().getActionName();
URL += ".action";
log.debug("actionname=" + name + "||fullActionName=" + URL);
if (name.equals("login") || name.equals("loginAccess")) {
// 如果用戶想登錄,則使之通過
return invocation.invoke();
}
Map session = invocation.getInvocationContext().getSession();
// TODO 在這里判斷用戶是否已經(jīng)登陸,更改此方法,和OnLineUserManager聯(lián)系起來,
//OnLineUserManager 是線程安全的,效率上可能會(huì)比較低!所以暫時(shí)還不更改!。
String success = (String) session.get(QxglConstants.AUTH_SUCCESS);
log.debug("success=" + success);
// 如果沒有登陸,那么就退出系統(tǒng)
if (success == null || !"true".equals(success)) {
log.debug("please login");
return Action.LOGIN;
}
String userid = (String) session.get("userid");
if (userid == null || "".equals(userid)) {
log.error("用戶id不能為空!");
return Action.LOGIN;
}
// 如果是超級管理員,那么直接返回
if ("admin1111222233334444555566admin".equals(userid)) {
return invocation.invoke();
}
UserModelServiceDao userModelServiceDao = (UserModelServiceDao) MyBeanUtil
.getBean("userModelServiceDao");
// 獲取當(dāng)前用戶所擁有的角色
List<QxglRole> userRoles = userModelServiceDao.getRoles(userid);
if (userRoles == null || userRoles.size() < 1) {
// 沒有任何角色
log.warn("此用戶" + userid + "沒有任何角色,沒有權(quán)限執(zhí)行任何功能");
return "noPermit";
}
List<QxglRole> urlRoles = userModelServiceDao.getRolesByUrl(URL);
// 如果此URL沒有賦給任何角色,說明是合法用戶就可以訪問
if (urlRoles == null || urlRoles.size() < 1) {
log.debug("此資源未賦給任何角色,合法用戶就可以訪問");
return invocation.invoke();
}
// 根據(jù)角色來判斷用戶是否有權(quán)限來使用當(dāng)前的URL(action)
boolean flag = false;// 如果有權(quán)限訪問設(shè)置為true;
int userLen = userRoles.size();
int urlLen = urlRoles.size();
QxglRole tempUserRole = null;
QxglRole tempUrlRole = null;
START:
for (int i = 0; i < userLen; i++) {
// 首先初始化
tempUserRole = null;
tempUrlRole = null;
tempUserRole = userRoles.get(i);
for (int j = 0; j < urlLen; j++) {
tempUrlRole = urlRoles.get(j);
if (tempUserRole.getId().equals(tempUrlRole.getId())) {
flag = true;
break START;
}
}
}
if (flag) {
log.debug("success auth");
return invocation.invoke();
} else {
//用戶如果在主頁面中輸入其他的任何鏈接,系統(tǒng)將自動(dòng)執(zhí)行l(wèi)ogout動(dòng)作,因?yàn)樵?sysmenu/top.jsp中配置了onunload事件。
log.warn("此用戶" + userid + "沒有權(quán)限執(zhí)行此功能"+URL);
return "noPermit";
}
}
}
在struts2的配置文件中配置
<package name="qxglmain" extends="struts-default" namespace="/">
<!-- 自定義攔截器 -->
<interceptors>
<interceptor name="auth"
class="com.work.qxgl.login.AuthorizationInterceptor" />
<interceptor name="ourLogger"
class="com.work.core.interceptor.LoggingInterceptor" />
<interceptor name="ourTimer"
class="com.work.core.interceptor.TimerInterceptor" />
<!-- 自定義攔截器堆棧 -->
<interceptor-stack name="qxglStack">
<interceptor-ref name="auth" /><!-- 權(quán)限控制 -->
<!-- 用來查看每個(gè)action執(zhí)行了多長時(shí)間,看執(zhí)行效率,只所以重新編寫,因?yàn)閤work的源代碼的日志級別低為INFO,我們配置的日志級別為ERROR。所以看不到了 -->
<interceptor-ref name="ourTimer" />
<interceptor-ref name="ourLogger" />
<!--
<interceptor-ref name="logger" /> -->
<!-- 引用默認(rèn)的攔截器堆棧 -->
<interceptor-ref name="defaultStack" />
</interceptor-stack>
</interceptors>
<!-- 重定義默認(rèn)攔截器堆棧 -->
<default-interceptor-ref name="qxglStack" />
<global-results>
<result name="login" type="redirectAction">login</result>
<result name="error">/qxgl/error.jsp</result>
<result name="noPermit">/qxgl/noPermit.jsp</result>
<result name="input" type="redirectAction">login</result>
</global-results>
<!-- exception的配置必須在global-results后面 -->
<global-exception-mappings>
<exception-mapping
exception="java.lang.NullPointerException" result="error" />
<exception-mapping exception="java.lang.Exception"
result="error" />
<exception-mapping
exception="com.work.core.exception.StorageException" result="error" />
</global-exception-mappings>
<action name="qxglmain"
class="com.work.qxgl.main.QxglMainAction">
<result>/qxgl/menutree/qxglmain.jsp</result>
</action>
<action name="sysmain"
class="com.work.qxgl.main.QxglMainAction" method="sysmain">
<result>/sysmenu/sysMain.jsp</result>
</action>
<action name="login" class="com.work.qxgl.login.LoginAction"
method="login">
<result>/login.jsp</result>
</action>
<action name="logout" class="com.work.qxgl.login.LogoutAction">
<result>/login.jsp</result>
</action>
<action name="loginAccess" class="com.work.qxgl.login.LoginAction">
<result type="redirectAction">sysmain</result>
<result name="input" >/login.jsp</result>
</action>
<action name="listOnLineUsers" class="com.work.qxgl.login.OnLineUserAction">
<result>/qxgl/onlineuser/onlineuser.jsp</result>
</action>
<action name="kickUser" class="com.work.qxgl.login.OnLineUserAction"
method="kickUser">
<result type="chain">listOnLineUsers</result>
</action>
<action name="listMenu" class="com.work.qxgl.main.QxglMainAction"
method="listMenu">
<result>/sysmenu/menu.jsp</result>
</action>
</package>
缺點(diǎn):
struts2的攔截器只能夠控制*.action,其他的jsp文件等會(huì)被忽略,所以通過struts2的攔截器實(shí)現(xiàn)權(quán)限控制有一定的缺陷。
我們可以通過編寫一個(gè)filter來控制其他請求的權(quán)限
package com.work.core.filter;
/**
* @author wangmingjie
* @date 2008-8-25下午10:09:26
*/
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.work.core.QxglConstants;
public class AuthFilter implements Filter {
private static Log log = LogFactory.getLog(AuthFilter.class);
public void init(FilterConfig filterConfig) throws ServletException {
if(log.isDebugEnabled()){
log.debug("初始化權(quán)限過濾器。");
}
}
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
/**
* 1,doFilter方法的第一個(gè)參數(shù)為ServletRequest對象。此對象給過濾器提供了對進(jìn)入的信息(包括
* 表單數(shù)據(jù)、cookie和HTTP請求頭)的完全訪問。第二個(gè)參數(shù)為ServletResponse,通常在簡單的過
* 濾器中忽略此參數(shù)。最后一個(gè)參數(shù)為FilterChain,此參數(shù)用來調(diào)用servlet或JSP頁。
*/
HttpServletRequest request = (HttpServletRequest) servletRequest;
/**
* 如果處理HTTP請求,并且需要訪問諸如getHeader或getCookies等在ServletRequest中
* 無法得到的方法,就要把此request對象構(gòu)造成HttpServletRequest
*/
HttpServletResponse response = (HttpServletResponse) servletResponse;
String currentURL = request.getRequestURI(); // 取得根目錄所對應(yīng)的絕對路徑:
HttpSession session = request.getSession(false);
//如果jsp就驗(yàn)證(login.jsp除外)
if (currentURL.indexOf(QxglConstants.LOGIN_PAGE)==-1 && currentURL.indexOf(".jsp")>-1 ) {
if(log.isDebugEnabled()){
log.debug("對jsp文件進(jìn)行權(quán)限驗(yàn)證。"+"請求的URL:"+currentURL);
}
// 判斷當(dāng)前頁是否是重定向以后的登錄頁面頁面,如果是就不做session的判斷,防止出現(xiàn)死循環(huán)
if(session == null || session.getAttribute(QxglConstants.AUTH_SUCCESS) == null ){
response.sendRedirect(request.getContextPath()+QxglConstants.LOGIN_PAGE);
return ;
}
}
// 加入filter鏈繼續(xù)向下執(zhí)行
filterChain.doFilter(request, response);
/**
* 調(diào)用FilterChain對象的doFilter方法。Filter接口的doFilter方法取一個(gè)FilterChain對象作 為它
* 的一個(gè)參數(shù)。在調(diào)用此對象的doFilter方法時(shí),激活下一個(gè)相關(guān)的過濾器。如果沒有另
* 一個(gè)過濾器與servlet或JSP頁面關(guān)聯(lián),則servlet或JSP頁面被激活。
*/
}
public void destroy() {
}
}
在web.xml中配置權(quán)限過濾器
<!-- 進(jìn)行權(quán)限驗(yàn)證 -->
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>
com.work.core.filter.AuthFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>