权限控制和session验证的实现 struts2spring权限控制session检查
程序员文章站
2022-04-25 13:35:11
...
最近项目(struts2+spring+mybatis)中做了一个权限控制,做个简单的介绍:
基本思路是:在struts2中做一个拦截器,对所有action进行拦截,去判断用户是否有执行该action的权限,有则执行action,无责跳转到权限error页面;当然了,如何判断是否有权限,有很多实现方式,这里我们是写了一个listener,在web容器启动时会去读取一个配置了所有action的权限id的property文件,那么在拦截器拦截到action时就可以用这个信息来判断当前用户是否有权限执行该action。session的验证就更简单了,只要一个拦截器就行,不需要listener。
首先是在struts.xml中配置拦截器:
再来看下拦截器的实现类:
这样一来,所有action在执行前都会执行该拦截器,而在拦截器的实现类中判断当前用户是否有权限时,用到了这样一个hashmap:
它是从哪里来的呢?这里就用到了Listener。
首先在web.xml中配置监听器:
之后当然是该监听器的实现类了:
注意到这里是读取common.properties,这个文件很简单:
这样就搞定了,最后补充一下session拦截器的实现类:
基本思路是:在struts2中做一个拦截器,对所有action进行拦截,去判断用户是否有执行该action的权限,有则执行action,无责跳转到权限error页面;当然了,如何判断是否有权限,有很多实现方式,这里我们是写了一个listener,在web容器启动时会去读取一个配置了所有action的权限id的property文件,那么在拦截器拦截到action时就可以用这个信息来判断当前用户是否有权限执行该action。session的验证就更简单了,只要一个拦截器就行,不需要listener。
首先是在struts.xml中配置拦截器:
<!-- 全局配置:拦截器和错误跳转 --> <package name="global" extends="struts-default"> <result-types> <result-type name="json" class="org.apache.struts2.json.JSONResult" /> </result-types> <interceptors> <!-- セッションインターセプター --> <interceptor name="sessionCheckInterceptor" class="jp.com.interceptor.SessionCheckInterceptor" /> <!-- ユーザ権限インターセプター --> <interceptor name="authCheckInterceptor" class="jp.com.interceptor.AuthCheckInterceptor" /> <!-- 基本的なスタック --> <interceptor-stack name="basicStack"> <interceptor-ref name="sessionCheckInterceptor" /> <interceptor-ref name="authCheckInterceptor" /> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <default-interceptor-ref name="basicStack" /> <global-results> <!-- リダイレクト --> <result name="login" type="redirect"> <param name="location">/web/auth/login.jsp</param> <param name="loginRedirectUrl">${loginRedirectUrl}</param> </result> <!-- リダイレクト --> <result name="redirect" type="redirectAction"> <param name="actionName">redirect</param> <param name="namespace">/common</param> <param name="redirectUrl">${redirectUrl}</param> </result> <!-- サーバメンテナンスエラー --> <result name="maintenance">/web/error/99001.jsp</result> <!-- システムエラー --> <result name="systemerror">/web/error/99002.jsp</result> <!-- セッション切れエラー --> <result name="sessiontimout">/web/error/99003.jsp</result> <!-- 二重送信エラー --> <result name="invalid.token">/web/error/99004.jsp</result> <!-- アカウントに権限が付与されない場合、ダイアログを表示される。 --> <result name="noPermit">/web/error/99005.jsp</result> </global-results> </package>
再来看下拦截器的实现类:
public class AuthCheckInterceptor extends MethodFilterInterceptor { /** log */ private static Log log = LogFactory.getLog( AuthCheckInterceptor.class ); @SuppressWarnings("unchecked") @Override protected String doIntercept( ActionInvocation invocation ) throws Exception { log.info( "AuthCheckInterceptor start" ); String interceptResult = null; HttpSession httpSession = ServletActionContext.getRequest().getSession(); // 获取action动作机能id String namespace = invocation.getProxy().getNamespace(); String actionname = invocation.getProxy().getActionName(); List<Integer> permisionLst = (List<Integer>) httpSession.getAttribute( "permision" ); String propKey = ""; if ( namespace != null ) { // 去除namespace中的'/' for ( int i = 0; i < namespace.length() && namespace.contains( "/" ); i++ ) { if ( namespace.charAt( i ) == '/' ) { namespace = namespace.substring( 0, i ) + namespace.substring( i + 1, namespace.length() ); } } propKey = namespace.toLowerCase() + "."; } propKey += actionname.toLowerCase(); Integer kinouId = KinouIdConsts.kinouID.get( propKey ); // 机能id存在,且机能id为-1(或用户权限包含该机能id),则进入机能 if ( ( kinouId != null && kinouId == -1 ) || ( permisionLst != null && permisionLst.contains( kinouId ) ) ) { interceptResult = invocation.invoke(); } // 无权限,则跳转无权限页面 else { interceptResult = "noPermit"; } log.info( "AuthCheckInterceptor end" ); return interceptResult; } }
这样一来,所有action在执行前都会执行该拦截器,而在拦截器的实现类中判断当前用户是否有权限时,用到了这样一个hashmap:
Integer kinouId = KinouIdConsts.kinouID.get( propKey );
它是从哪里来的呢?这里就用到了Listener。
首先在web.xml中配置监听器:
<listener> <listener-class>jp.com.listener.PropertyLoaderListener</listener-class> </listener>
之后当然是该监听器的实现类了:
public class PropertyLoaderListener implements ServletContextListener { @Override public void contextDestroyed( ServletContextEvent arg0 ) { // TODO Auto-generated method stub } @Override public void contextInitialized( ServletContextEvent arg0 ) { // プロパティファイルを読み込む String path = "WEB-INF/conf/common.properties"; String filePath = arg0.getServletContext().getRealPath( path ); FileInputStream inputFile; try { Properties prop = new Properties(); inputFile = new FileInputStream( filePath ); InputStreamReader reader = new InputStreamReader( inputFile ); prop.load( reader ); // 遍历 Properties Iterator it = prop.entrySet().iterator(); while ( it.hasNext() ) { Map.Entry entry = (Map.Entry) it.next(); String key = (String) entry.getKey(); Integer value = Integer.parseInt( (String) entry.getValue() ); KinouIdConsts.kinouID.put( key.toLowerCase(), value ); } } catch ( Exception e ) { e.printStackTrace(); } } }
注意到这里是读取common.properties,这个文件很简单:
#权限机能配置 #格式:namespace.action=值 # [-1]:不進行權限驗證 [其他值]:進行權限驗證 # (未配入的值一律当"无权限"处理) mainmenu.mainmenu=-1 opemgr.opemgrmenu=9 ...
这样就搞定了,最后补充一下session拦截器的实现类:
public class SessionCheckInterceptor extends MethodFilterInterceptor { /** log */ private static Log log = LogFactory.getLog(SessionCheckInterceptor.class); @Override protected String doIntercept(ActionInvocation invocation) throws Exception { log.info("doIntercept start"); //如果是登录使用的action,用户退出的action,直接强制不进行session过期的验证 if(LoginAction.class == invocation.getAction().getClass() || LogoutAction.class == invocation.getAction().getClass()) { return invocation.invoke(); } //其他的所有的action都要使用判断session是否过期的拦截器站 // Get operator id from session OperatorVO opeObj = (OperatorVO) invocation.getInvocationContext() .getSession().get("ope_obj"); if (null == opeObj) { return "sessiontimout"; } log.info("doIntercept end"); return invocation.invoke(); } }
推荐阅读