zoukankan      html  css  js  c++  java
  • [置顶] 使用struts拦截器+注解实现网络安全要求中的日志审计功能

    J2EE项目中出于安全的角度考虑,用户行为审计日志功能必不可少,通过本demo可以实现如下功能:
    1.项目中记录审计日志的方法.
    2.struts拦截器的基本配置和使用方法.
    3.struts拦截器中获得用户访问的类和访问的方法.
    4.注解的基本用法,以及在struts拦截器中使用注解.

    5.struts拦截器中获得用户访问的IP地址,可扩展对IP进行鉴权功能(允许或限制某些IP).


    系统运行一段时间后,通过这些审计日志还可以挖掘的内容:
    1.用户行为审计,发现最异常情况及时调整和处理.
    2.统计哪些模块访问的频度最高,调整界面把用户访问最高的模块放到显著位置.
    3.统计各个功能模块方法的访问时长,有助于我们进行程序性能的优化.
    4.用户关联行为分析,优化访问流程,提高用户体验.

    项目结构:

    功能代码:

    AuditLogInterceptor.java(知识点见注释):

    package com.tgb.lk.auditlog;
    
    import java.lang.reflect.Method;
    import java.util.Date;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
    import com.tgb.lk.model.AuditLog;
    
    public class AuditLogInterceptor extends MethodFilterInterceptor {
    
    	@Override
    	protected String doIntercept(ActionInvocation actioninvocation)
    			throws Exception {
    		AuditLog auditLog = new AuditLog();
    
    		auditLog.setStartTime(new Date());// 设置开始时间
    		String result = actioninvocation.invoke();// 递归调用拦截器
    		auditLog.setEndTime(new Date());// 设置结束时间
    
    		String userId = (String) ServletActionContext.getRequest().getSession()
    				.getAttribute("userId");
    		auditLog.setUserId(userId);// 设置登录用户的Id,在用户登录时把id保存到session中,这里可扩展判断用户是否登录的验证和权限验证
    		/*String name = actioninvocation.getInvocationContext().getName();
    		String methodName = "";
    
    		// struts.xml中配置:
    		// <package name="user" namespace="/user" extends="default">
    		// <action name="user_*" class="com.tgb.lk.action.UserAction" method="{1}">
    		//
    		// 访问地址: http://127.0.0.1:8080/AuditLogDemo/user/user_add
    		// http://127.0.0.1:8080/AuditLogDemo/user/user_del
    		if (name != null && name.contains("_")) {
    			methodName = name.substring(name.indexOf("_") + 1, name.length());
    		}*/
    		String methodName = actioninvocation.getProxy().getMethod();
    		if (methodName.length() > 0) {
    			Object action = actioninvocation.getAction();
    			Class clazz = action.getClass();
    			// 如果设置了注解则读取注解的内容,如果没有设置注解则记录登录的class名
    			if (clazz.isAnnotationPresent(AuditLogger.class)) {
    				AuditLogger talClazz = (AuditLogger) clazz
    						.getAnnotation(AuditLogger.class);
    				auditLog.setClazz(talClazz.log());
    			} else {
    				auditLog.setClazz(clazz.getSimpleName());
    			}
    
    			Method method = action.getClass().getMethod(methodName, null);
    			// 如果设置了注解则读取注解的内容,如果没有设置注解则记录登录的method名
    			if (method.isAnnotationPresent(AuditLogger.class)) {
    				AuditLogger alm = (AuditLogger) method
    						.getAnnotation(AuditLogger.class);
    				auditLog.setMethod(alm.log());
    			} else {
    				auditLog.setMethod(methodName);
    			}
    			String ip = ServletActionContext.getRequest().getRemoteAddr();
    			auditLog.setIp(ip);// 记录登录的IP,这里还可以对IP进行鉴权功能(允许或限制某些IP)
    			auditLog.setResult(result);// 记录登录时返回的结果.
    
    			System.out.println(auditLog);
    			// auditLogService.save(auditLog); //保存入库
    		}
    		return result; // 跳转
    	}
    
    }
    


    struts.xml:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
    	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    	"http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
    
    	<constant name="struts.devMode" value="true" />
    	<package name="default" namespace="/" extends="struts-default">
    		<interceptors>
    			<!-- 日志审计拦截器 -->
    			<interceptor name="auditlog"
    				class="com.tgb.lk.auditlog.AuditLogInterceptor" />
    			<interceptor-stack name="myStack">
    				<interceptor-ref name="auditlog">
    					<!--
    						配置到excludeMethods中的方法将不记录日志
    					-->
    					<param name="excludeMethods">testExclude</param>
    				</interceptor-ref>
    				<!--
    					struts默认的拦截器
    				-->
    				<interceptor-ref name="defaultStack" />
    			</interceptor-stack>
    		</interceptors>
    		<default-interceptor-ref name="myStack" />
    	</package>
    	
    	<!-- 注意extends="default" -->
    	<package name="user" namespace="/user" extends="default">
    		<action name="user_*" class="com.tgb.lk.action.UserAction" method="{1}">
    			<result name="add">/index.jsp</result>
    			<result name="del">/index.jsp</result>
    			<result name="modify">/index.jsp</result>
    			<result name="view">/index.jsp</result>
    		</action>
    	</package>
    
    </struts>
    


    注解类AuditLogger.java:

    package com.tgb.lk.auditlog;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target( { java.lang.annotation.ElementType.METHOD,
    		java.lang.annotation.ElementType.TYPE })
    public @interface AuditLogger {
    
    	public abstract String log();
    
    }
    

    Struts的Action中使用配置:

    package com.tgb.lk.action;
    
    import com.tgb.lk.auditlog.AuditLogger;
    
    @AuditLogger(log = "用户管理")
    public class UserAction {
    
    	@AuditLogger(log = "添加用户")
    	public String add() {
    		return "add";
    	}
    
    	@AuditLogger(log = "删除用户")
    	public String del() {
    		return "del";
    	}
    
    	@AuditLogger(log = "修改用户")
    	public String modify() {
    		return "modify";
    	}
    
    	@AuditLogger(log = "浏览用户信息")
    	public String view() {
    		return "view";
    	}
    
    }
    

    实体类AuditLog.java

    package com.tgb.lk.model;
    
    import java.util.Date;
    
    public class AuditLog {
    	private int id;
    	private String userId;
    	private Date startTime;
    	private Date endTime;
    	private String ip;
    	private String clazz;
    	private String method;
    	private String result;
    
    	public int getId() {
    		return id;
    	}
    
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	public String getUserId() {
    		return userId;
    	}
    
    	public void setUserId(String userId) {
    		this.userId = userId;
    	}
    
    	public Date getStartTime() {
    		return startTime;
    	}
    
    	public void setStartTime(Date startTime) {
    		this.startTime = startTime;
    	}
    
    	public Date getEndTime() {
    		return endTime;
    	}
    
    	public void setEndTime(Date endTime) {
    		this.endTime = endTime;
    	}
    
    	public String getIp() {
    		return ip;
    	}
    
    	public void setIp(String ip) {
    		this.ip = ip;
    	}
    
    	public String getClazz() {
    		return clazz;
    	}
    
    	public void setClazz(String clazz) {
    		this.clazz = clazz;
    	}
    
    	public String getMethod() {
    		return method;
    	}
    
    	public void setMethod(String method) {
    		this.method = method;
    	}
    
    	public String getResult() {
    		return result;
    	}
    
    	public void setResult(String result) {
    		this.result = result;
    	}
    
    	@Override
    	public String toString() {
    		return "AuditLog [id=" + id + ", userId=" + userId + ", ip=" + ip
    				+ ", startTime=" + startTime + ", endTime=" + endTime
    				+ ", clazz=" + clazz + ", method=" + method + ", result="
    				+ result + "]";
    	}
    
    }
    


    代码下载地址: http://download.csdn.net/detail/lk_blog/6003581

    限于本人水平有限,很多地方写的并不完美,望大家不吝赐教,希望在和大家的交流中得到提高.


  • 相关阅读:
    crazyflie2.0 RCC时钟知识
    quick-cocos2d-x开发工具sublime text及其强力插件QuickXDev
    [Swift通天遁地]一、超级工具-(16)使用JTAppleCalendar制作美观的日历
    [Swift]LeetCode186. 翻转字符串中的单词 II $ Reverse Words in a String II
    [SQL]LeetCode185. 部门工资前三高的员工 | Department Top Three Salaries
    [Swift通天遁地]一、超级工具-(15)使用SCLAlertView制作强大的Alert警告窗口和Input编辑窗口
    [SQL]LeetCode184. 部门工资最高的员工 | Department Highest Salary
    [Swift通天遁地]一、超级工具-(14)使用SweetAlert制作漂亮的自定义Alert窗口
    [Swift]关键字:Self、self与super
    [Swift]LeetCode964. 表示数字的最少运算符 | Least Operators to Express Number
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3279969.html
Copyright © 2011-2022 走看看