在前面 一步一步做项目(18)拦截用户日志的基础上进行,由于前面已经建立了一些内容,这里可以直接使用。
拦截器
同样利用拦截器原理,从MethodFilterInterceptor继承,创建用户访问控制拦截器,由于系统比较简单,就只是提供键值对进行了权限配置,配置信息存储在Messages.properties文件中,如果要进行复杂的授权操作,可以通过数据库来进行存取,代码如下:
package cn.lut.curiezhang.interceptor;
import java.util.ArrayList;
import java.util.Map;
import java.util.ResourceBundle;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import cn.lut.curiezhang.action.LoginAction;
import cn.lut.curiezhang.model.Users;
/**
* 登录拦截器
* @author curiezhang
*/
@SuppressWarnings("serial")
public class AccessInterceptor extends MethodFilterInterceptor {
public static final String USER_SESSION = ResourceBundle.getBundle("Messages").getString("Application.sessionName");
public static final String ADMIN_ACCESS_STUDENT = ResourceBundle.getBundle("Messages").getString("Admin.access.STUDENT");
public static final String ADMIN_ACCESS_COLLEGE = ResourceBundle.getBundle("Messages").getString("Admin.access.COLLEGE");
public static final String ADMIN_ACCESS_SITE = ResourceBundle.getBundle("Messages").getString("Admin.access.SITE");
public static final String ADMIN_ACCESS_ADMIN = ADMIN_ACCESS_COLLEGE + "," + ADMIN_ACCESS_SITE + "," +
ResourceBundle.getBundle("Messages").getString("Admin.access.ADMIN");
private static final Logger log = LogManager.getLogger(AccessInterceptor.class);
@Override
protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
log.debug("cmis:访问控制 > 开始拦截");
HttpServletRequest request = ServletActionContext.getRequest();
ActionContext actionContext = actionInvocation.getInvocationContext();
Map<String, Object> session = actionContext.getSession();
//except login action
Object action = actionInvocation.getAction();
if (action instanceof LoginAction) {
return actionInvocation.invoke();
}
//check session
Users user = (Users)session.get(USER_SESSION);
String visitUrl = request.getRequestURI();
String[] split;
split = visitUrl.split("/");
if(null == user) {
log.debug("cmis:访问控制 > 请登录");
String key;
key = split[2];
log.debug("cmis:访问控制 > key={}", key);
if("admin".equals(key)) {
return "loginAdmin";
} else {
return "login";
}
} else {
String key;
switch (user.getStatus().getIndex()) {
case 0:
log.debug("cmis:访问控制 0 > status={}", user.getStatus().getIndex());
split = visitUrl.split("/");
key = split[2];
log.debug("cmis:访问控制0 > key={}", key);
String[] front = {"applyForTheCollegeId", "userId", "examineeId", "studentId", "assignExaminationRoomId"};
ArrayList<String> frontValue = new ArrayList<String>();
for(String str : front) {
if(request.getParameter(str) != null) {
log.debug("cmis:访问控制0 > str={},value={}", str, request.getParameter(str));
frontValue.add(request.getParameter(str));
}
}
// 如果访问其他用户,则不能访问
if (!frontValue.isEmpty()) {
for(String str : frontValue) {
if(!str.contains(user.getUserId()))
return "noAccess";
}
}
// 如果访问其他资源,则没有权限
if(!ADMIN_ACCESS_STUDENT.contains(key)) {
return "noPermission";
}
break;
case 1:
log.debug("cmis:访问控制 1 > status={}", user.getStatus().getIndex());
visitUrl = request.getRequestURI();
split = visitUrl.split("/");
key = split[3];
log.debug("cmis:访问控制1 > key={}", key);
String[] front1 = {"collegeId", "examinationApplyId", "enrollmentId", "schoolAdmissionBrochureId", "userId"};
ArrayList<String> front1Value = new ArrayList<String>();
for(String str : front1) {
if(request.getParameter(str) != null) {
log.debug("cmis:访问控制1 > str={},value={}", str, request.getParameter(str));
front1Value.add(request.getParameter(str));
}
}
if (!front1Value.isEmpty()) {
for(String str : front1Value) {
if(!str.contains(user.getUserId()))
return "noAccess";
}
}
if(!ADMIN_ACCESS_COLLEGE.contains(key)) {
return "noPermission";
}
break;
case 2:
log.debug("cmis:访问控制2 > status={}", user.getStatus().getIndex());
visitUrl = request.getRequestURI();
split = visitUrl.split("/");
key = split[3];
log.debug("cmis:访问控制2 > key={}", key);
String[] front2 = {"examinationPointId", "userId", "agendaId", "examinationRoomId", "examinationArrangementId", "assignExaminationRoomId"};
ArrayList<String> front2Value = new ArrayList<String>();
for(String str : front2) {
if(request.getParameter(str) != null) {
log.debug("cmis:访问控制2 > str={},value={}", str, request.getParameter(str));
front2Value.add(request.getParameter(str));
}
}
// 如果访问其他用户,则不能访问
if (!front2Value.isEmpty()) {
for(String str : front2Value) {
if(!str.contains(user.getUserId()))
return "noAccess";
}
}
if(!ADMIN_ACCESS_SITE.contains(key)) {
return "noPermission";
}
break;
case 3:
log.debug("cmis:访问控制3 > status={}", user.getStatus().getIndex());
visitUrl = request.getRequestURI();
split = visitUrl.split("/");
key = split[3];
log.debug("cmis:访问控制3 > key={}", key);
if(!ADMIN_ACCESS_ADMIN.contains(key)) {
return "noPermission";
}
break;
default:
return "noPermission";
}
}
return actionInvocation.invoke();//go on
}
}
这里面用到了一些属性值,需要在Messages.properties文件中进行声明,如下所示:
Application.sessionName=userSession
Admin.access.STUDENT=publicNotice
Admin.access.COLLEGE=publicNotice
Admin.access.SITE=publicNotice
Admin.access.ADMIN=index,users,userLog,publicNotice,examinee,discipline,countyDistrict
Admin.access.error=\u6743\u9650\u9519\u8BEF
Admin.access.noPermission=\u6CA1\u6709\u8BBF\u95EE\u6743\u9650\uFF0C\u8BF7\u767B\u5F55\u540E\u518D\u8BD5\u6216\u8054\u7CFB\u7BA1\u7406\u5458\uFF01
Admin.access.noAccess=\u6CA1\u6709\u8BBF\u95EE\u6743\u9650\uFF0C\u8BF7\u66F4\u6362\u7528\u6237\u767B\u5F55\u540E\u518D\u8BD5\u6216\u8054\u7CFB\u7BA1\u7406\u5458\uFF01
配置
创建了AccessInterceptor拦截器类,就要进行配置,在中间添加配置,之后,在action中引用配置,让自定义拦截器起作用,配置如下:
<interceptors>
<interceptor name="auth" class="cn.lut.curiezhang.interceptor.AccessInterceptor" />
<interceptor-stack name="authStack">
<interceptor-ref name="auth"/>
</interceptor-stack>
<interceptor name="log" class="cn.lut.curiezhang.interceptor.UserLogInterceptor" />
<interceptor-stack name="logStack">
<interceptor-ref name="log">
</interceptor-ref>
</interceptor-stack>
</interceptors>
<global-results>
<!-- 定义名为exception的全局result -->
<result name="loginAdmin" type="redirect">/login/login.jsp</result>
<result name="noAccess" type="redirect">/admin/error/noAccess.jsp</result>
<result name="noPermission" type="redirect">/admin/error/noPermission.jsp</result>
</global-results>
前面的interceptor是用户权限拦截器,后面的interceptor是用户日志拦截器,引用配置方法如下:
<action name="index" class="cn.lut.curiezhang.action.AdminAction" method="index">
<result name="success">index.jsp</result>
<interceptor-ref name="logStack"/>
<interceptor-ref name="authStack"/>
<interceptor-ref name="basicStack"/>
</action>
注意,这里interceptor-ref指定的logStack,就是前面配置的日志拦截器栈信息,这里interceptor-ref指定的authStack,就是前面配置的访问控制拦截器栈信息,这样,只要访问该链接,就会记录访问日志,然后,验证是否具有权限,因此,对应的配置文件,都需要进行相应的处理,以便让权限验证起作用。
从这里可以看出,要想产生一个易于修改的应用,还是比较困难的,而且,越到后面添加类似的功能,需要修改的就越多,就越不容易。当然,这样的修改比较机械,还是简单的。
运行
所有的配置修改好了以后,只要使用action访问的地址,就都会被访问控制拦截器拦截,例如在地址栏输入:http://localhost:8089/cmis/admin/index,如果没有登录,就会要求用户登录,弹出登录页面,运行截图如下:
用户登录后,即可进行相应的操作,如下图所示:
当然,这里只是一个简单的演示,但基本原理是一样的,其他的未登录的访问,都会要求用户进行登录,如果访问了其他没有权限的资源,会进入没有权限页面,当然,这个页面需要读者自己补全,这里不再赘述。