单击导航栏上的"角色管理"超链接,跳转到角色管理界面,在该界面上显示所有角色,并提供角色的增加和删除、修改超链接。

  1.增加新角色(角色授权)

    流程:单击增加新角色超链接->Action查询出所有的权限保存到值栈并转到添加新角色页面->填写表单并提交->Action保存表单->重定向到角色管理Action

    技术点:表单提交的权限列表时一个整型数组,需要在Action中进行接收并调用相关方法转换成Rright列表;使用到了一些JQuery技术实现更友好的前端交互。

    【Java EE 学习 76 上】【数据采集系统第八天】【角色授权】【用户授权】【权限的粗粒度控制】【权限的细粒度控制】

  JQuery代码:

 1 <script type="text/javascript">
 2     $().ready(function(){
 3         $("button[id='toRight']").unbind("click");
 4         $("button[id='toRight']").bind("click",function(){
 5             var noneOwnRights=$("select[name='noneOwnRights']");
 6             var ownRights=$("select[name='ownRights']");
 7             $("select[name='ownRights'] option:selected").each(function(){
 8                 noneOwnRights.prepend($(this).clone());
 9                 $(this).remove();
10             });
11             return false;
12         });
13         $("button[id='toLeft']").unbind("click");
14         $("button[id='toLeft']").bind("click",function(){
15             var noneOwnRights=$("select[name='noneOwnRights']");
16             var ownRights=$("select[name='ownRights']");
17             $("select[name='noneOwnRights'] option:selected").each(function(){
18                 ownRights.prepend($(this).clone());
19                 $(this).remove();
20             });
21             return false;
22         });
23         $("button[id='allToRight']").unbind("click");
24         $("button[id='allToRight']").bind("click",function(){
25             var noneOwnRights=$("select[name='noneOwnRights']");
26             var ownRights=$("select[name='ownRights']");
27             $("select[name='ownRights'] option").each(function(){
28                 noneOwnRights.append($(this).clone());
29                 $(this).remove();
30             });
31             return false;
32         });
33         $("button[id='allToLeft']").unbind("click");
34         $("button[id='allToLeft']").bind("click",function(){
35             var noneOwnRights=$("select[name='noneOwnRights']");
36             var ownRights=$("select[name='ownRights']");
37             $("select[name='noneOwnRights'] option").each(function(){
38                 ownRights.append($(this).clone());
39                 $(this).remove();
40             });
41             return false;
42         });
43         $("#submit").unbind("click");
44         $("#submit").bind("click",function(){
45             $("select[name='ownRights'] option").each(function(){
46                 $(this).attr("selected","selected");
47             });
48             return true;
49         });
50     });
51 </script>

  2.角色修改和添加使用的方法是同一个方法,略

  3.角色删除略。

二、用户授权

  形式和流程和角色授权完全一致,略。

三、权限的粗粒度控制

  所谓的权限的粗粒度控制指的是改造登陆拦截器使其成为权限控制拦截器,当用户访问某个资源的时候将会根据不同的访问地址判断是否有权限访问,如果有权限访问则放行,否则跳转到错误提示页。

  权限控制拦截器中判断权限的流程之前说过了,如下图所示:

  【Java EE 学习 76 上】【数据采集系统第八天】【角色授权】【用户授权】【权限的粗粒度控制】【权限的细粒度控制】

  1.实现权限控制判断的代码封装到了工具类ValidateUtils的hasRight方法中:

 1 // 验证是否有权限的验证方法
 2     public static boolean hasRight(String namespace, String actionName, HttpServletRequest request,Action action) {
 3         String url = namespace + "/"
 4                 + (actionName.contains("?") ? actionName.substring(0, actionName.indexOf("?")) : actionName)
 5                 + ".action";
 6         // TODO 将权限列表放入到ServletContext中的方法
 7         HttpSession session = request.getSession();
 8         ServletContext sc = session.getServletContext();
 9         Map<String, Right> allRights = (Map<String, Right>) sc.getAttribute("all_rights_map");
10         Right right = allRights.get(url);
11         // 如果是公共资源直接方放过
12         if (right == null || right.getCommon()) {
13 //            System.out.println("访问公共资源,即将放行!");
14             return true;
15         } else {
16             User user = (User) session.getAttribute("user");
17             // 判断是否已经登陆
18             if (user == null) {
19                 return false;
20             } else {
21                 // 如果实现了UserAware接口
22                 if (action != null && action instanceof UserAware) {
23                     UserAware userAware = (UserAware) action;
24                     userAware.setUser(user);
25                 }
26                 // 如果是超级管理员直接放行
27                 if (user.getSuperAdmin()) {
28                     return true;
29                     // 否则先检查是否有权限
30                 } else {
31                     if (user.hasRight(right)) {
32                         return true;
33                     } else {
34                         return false;
35                     }
36                 }
37             }
38         }
39     }

    上面代码中的粗体部分是获取放到application作用域中的所有权限Map,key值是url,value值是对应的Right对象。

  2.拦截器代码调用工具方法进行判断

 1 package com.kdyzm.struts.interceptors;
 2 
 3 import java.util.Map;
 4 
 5 import javax.servlet.ServletContext;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpSession;
 8 
 9 import org.apache.struts2.ServletActionContext;
10 
11 import com.kdyzm.domain.User;
12 import com.kdyzm.domain.security.Right;
13 import com.kdyzm.struts.action.aware.UserAware;
14 import com.kdyzm.utils.ValidateUtils;
15 import com.opensymphony.xwork2.Action;
16 import com.opensymphony.xwork2.ActionInvocation;
17 import com.opensymphony.xwork2.ActionProxy;
18 import com.opensymphony.xwork2.interceptor.Interceptor;
19 
20 /**
21  * 只要请求了Action就会默认访问该拦截器
22  * 登陆拦截器
23  * @author kdyzm
24  *
25  */
26 public class LoginInterceptor implements Interceptor{
27     private static final long serialVersionUID = 7321012192261008127L;
28 
29     @Override
30     public void destroy() {
31         System.out.println("登录拦截器被销毁!");
32     }
33 
34     @Override
35     public void init() {
36         System.out.println("登录拦截器初始化!");
37     }
38     /**
39      *    对登录拦截器进行改造使其成为权限过滤拦截器
40      */
41     @SuppressWarnings("unchecked")
42     @Override
43     public String intercept(ActionInvocation invocation) throws Exception {
44         //首先获取请求的Action的名称
45         ActionProxy actionProxy=invocation.getProxy();
46         String namespace=actionProxy.getNamespace();
47         String actionName=actionProxy.getActionName();
48         if(namespace==null||"/".equals(namespace)){
49             namespace="";
50         }
51         HttpServletRequest request=ServletActionContext.getRequest();
52         boolean result=ValidateUtils.hasRight(namespace, actionName, request, (Action)invocation.getAction());
53         if(result==true){
54             return invocation.invoke();
55         }else{
56             return "no_right_error";
57         }
58     }
59 }

  3.配置struts2的global-result

<global-results>
            <result name="toLoginPage">/index.jsp</result>
            <!-- 定义全局结果类型,将编辑页面之后的返回页面定义为全局结果类型 -->
            <result name="toDesignSurveyPageAction" type="redirectAction">
                <param name="surveyId">${surveyId}</param>
                <param name="namespace">/</param>
                <param name="actionName">SurveyAction_designSurveyPage.action</param>
            </result>
            <result name="no_right_error">/error/no_right_error.jsp</result>
        </global-results>

四、将所有权限放到application作用域

  在权限控制的过程中会经常需要查询权限,如果每次都查询数据库中会对数据库造成很大的负担,最好的方式是将其放到内存,而且使用Map的数据结构更加方便的查询。

  将权限集合拿到内存的时机就是tomcat启动完成之前,这里借助spring容器的监听器实现该功能。

  实现的技术要点:

  1.如何获取application对象,在struts2中通过ServletContextAware接口可以将ServletContext注入到Action,在这里由于spring初始化的时候strus2还没有初始化,所以就不能通过实现struts2的接口来注入application对象了;spring提供了相同的方式注入application对象,注意不要导错了包,接口名都是ServletContextAware。

  2.直接通过注解的方式注入spring容器,在包扫描的规则中添加com.kdyzm.listener。

 1 package com.kdyzm.listener;
 2 
 3 import java.util.Collection;
 4 import java.util.HashMap;
 5 import java.util.Map;
 6 
 7 import javax.annotation.Resource;
 8 import javax.servlet.ServletContext;
 9 
10 import org.springframework.context.ApplicationEvent;
11 import org.springframework.context.ApplicationListener;
12 import org.springframework.context.event.ContextRefreshedEvent;
13 import org.springframework.stereotype.Component;
14 import org.springframework.web.context.ServletContextAware;
15 
16 import com.kdyzm.domain.security.Right;
17 import com.kdyzm.service.RightService;
18 
19 /**
20  * 初始化权限数据的监听类
21  * 该监听器的作用就是将所有的权限放入ServletContext中
22  * Spring容器初始化的时候struts2还没有初始化,所以不能使用struts2的ServletContextAware获取SerlvetContext对象。
23  * 但是spring提供了相同的机制获取ServletContext对象,而且使用的方法和接口也是完全相同。
24  * 这里还有一个非常重要的东西:注入sc一定在前。
25  * 
26  * 直接使用注解注入到spring容器,不需要对配置文件进行修改
27  * @author kdyzm
28  *
29  */
30 @Component
31 public class InitRightListener implements ApplicationListener,ServletContextAware{
32     private ServletContext sc;
33     @Resource(name="rightService")
34     private RightService rightService;
35     @Override
36     public void onApplicationEvent(ApplicationEvent event) {
37         //这里所有的ApplicationContext的事件都会不获到,所以必须进行判断已进行分类处理
38         if(event instanceof ContextRefreshedEvent){
39             Collection<Right> rights=rightService.getAllRights();
40             Map<String,Right>rightMap=new HashMap<String,Right>();
41             for(Right right: rights){
42                 System.out.println(right.getRightUrl()+":"+right.getCommon());
43                 rightMap.put(right.getRightUrl(), right);
44             }
45             if(sc!=null){
46                 sc.setAttribute("all_rights_map", rightMap);
47                 System.out.println("初始化RightMap成功!");
48             }else{
49                 System.out.println("ServletContext对象为空,初始化RightMap对象失败!");
50             }
51         }
52     }
53     
54     //注入ServletContext
55     @Override
56     public void setServletContext(ServletContext servletContext) {
57         System.out.println("注入ServletContext对象");
58         this.sc=servletContext;
59     }
60 
61 }

    ApplicationContext.xml配置文件也需要修改:

1 <context:component-scan
2         base-package="com.kdyzm.dao.impl,com.kdyzm.service.impl,com.kdyzm.struts.action,com.kdyzm.dao.base.impl,com.kdyzm.listener"></context:component-scan>

五、权限的细粒度控制

  1.什么是细粒度控制

  所谓细粒度控制就是和粗粒度控制相比较而言的,粗粒度控制旨在当用户访问了无权限访问的资源的时候,拦截其访问;细粒度控制旨在更深一步细化权限控制,不让用户有机会访问无权限访问的资源,也就是说控制关键标签的显示,比如超链接、提交按钮等。

  2.实现细粒度控制的方法

  方法就是重写struts2的标签类,覆盖掉struts2提供的class文件,这种方式在tomcat下是没有问题的,在其它环境下没有测试,结果未知,最好的方法就是将jar包中对应的class文件剔除,这样类就唯一了。

  3注意事项

  一定使用struts2完全匹配版本的源代码,否则版本不同特别是差异比较大的,非常有可能会出现意料之外的异常。

  4.重写的两个类

    org.apache.struts2.views.jsp.ui.AnchorTag  对应着<s:a></s:a>

    org.apache.struts2.views.jsp.ui.SubmitTag   对应着<s:submit></s:submit>

    (1)重写AnchorTag标签类

  重写AnchorTag类比较简单,只需要重写doEndTag方法即可,注意,该类有属性pageContext,可以直接获取HttpServletRequest对象;第四个参数为Action对象,这里没有就填写NULL,Action对象参数的目的是为了将User对象注入到Action。

 1 //a标签只需要重写一个方法就行
 2     @Override
 3     public int doEndTag() throws JspException {
 4         if(namespace==null||"/".equals(namespace)){
 5             namespace="";
 6         }
 7         if(action==null){
 8             action="";
 9         }else{
10             if(action.endsWith(".action")){
11                 action=action.substring(0, action.indexOf("."));
12             }
13         }
14         boolean result=ValidateUtils.hasRight(namespace, action, (HttpServletRequest)pageContext.getRequest(), null);
15 //        System.out.println("即将访问"+namespace+action);
16         if(result==true){
17 //            System.out.println("有权限,即将放行!");
18             return super.doEndTag();
19         }else{
20 //            System.out.println("没有权限,即将跳过标签体!");
21             return SKIP_BODY;
22         }
23     }

    完整代码:

  1 /*
  2  * $Id: AnchorTag.java 768855 2009-04-27 02:09:35Z wesw $
  3  *
  4  * Licensed to the Apache Software Foundation (ASF) under one
  5  * or more contributor license agreements.  See the NOTICE file
  6  * distributed with this work for additional information
  7  * regarding copyright ownership.  The ASF licenses this file
  8  * to you under the Apache License, Version 2.0 (the
  9  * "License"); you may not use this file except in compliance
 10  * with the License.  You may obtain a copy of the License at
 11  *
 12  *  http://www.apache.org/licenses/LICENSE-2.0
 13  *
 14  * Unless required by applicable law or agreed to in writing,
 15  * software distributed under the License is distributed on an
 16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  * KIND, either express or implied.  See the License for the
 18  * specific language governing permissions and limitations
 19  * under the License.
 20  * 
 21  * 对应着<s:a>标签,重写该类中的某个方法即可完成对权限细粒度的划分
 22  */
 23 
 24 package org.apache.struts2.views.jsp.ui;
 25 
 26 import javax.servlet.http.HttpServletRequest;
 27 import javax.servlet.http.HttpServletResponse;
 28 import javax.servlet.jsp.JspException;
 29 
 30 import org.apache.struts2.components.Anchor;
 31 import org.apache.struts2.components.Component;
 32 
 33 import com.kdyzm.utils.ValidateUtils;
 34 import com.opensymphony.xwork2.util.ValueStack;
 35 
 36 /**
 37  * @see Anchor
 38  */
 39 public class AnchorTag extends AbstractClosingTag {
 40 
 41     private static final long serialVersionUID = -1034616578492431113L;
 42 
 43     protected String href;
 44     protected String includeParams;
 45     protected String scheme;
 46     protected String action;
 47     protected String namespace;
 48     protected String method;
 49     protected String encode;
 50     protected String includeContext;
 51     protected String escapeAmp;
 52     protected String portletMode;
 53     protected String windowState;
 54     protected String portletUrlType;
 55     protected String anchor;
 56     protected String forceAddSchemeHostAndPort;
 57     
 58     public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
 59         return new Anchor(stack, req, res);
 60     }
 61     
 62     protected void populateParams() {
 63         super.populateParams();
 64 
 65         Anchor tag = (Anchor) component;
 66         tag.setHref(href);
 67         tag.setIncludeParams(includeParams);
 68         tag.setScheme(scheme);
 69         tag.setValue(value);
 70         tag.setMethod(method);
 71         tag.setNamespace(namespace);
 72         tag.setAction(action);
 73         tag.setPortletMode(portletMode);
 74         tag.setPortletUrlType(portletUrlType);
 75         tag.setWindowState(windowState);
 76         tag.setAnchor(anchor);
 77 
 78         if (encode != null) {
 79             tag.setEncode(Boolean.valueOf(encode).booleanValue());
 80         }
 81         if (includeContext != null) {
 82             tag.setIncludeContext(Boolean.valueOf(includeContext).booleanValue());
 83         }
 84         if (escapeAmp != null) {
 85             tag.setEscapeAmp(Boolean.valueOf(escapeAmp).booleanValue());
 86         }
 87         if (forceAddSchemeHostAndPort != null) {
 88             tag.setForceAddSchemeHostAndPort(Boolean.valueOf(forceAddSchemeHostAndPort).booleanValue());
 89         }
 90     }
 91     
 92     public void setHref(String href) {
 93         this.href = href;
 94     }
 95 
 96     public void setEncode(String encode) {
 97         this.encode = encode;
 98     }
 99 
100     public void setIncludeContext(String includeContext) {
101         this.includeContext = includeContext;
102     }
103 
104     public void setEscapeAmp(String escapeAmp) {
105         this.escapeAmp = escapeAmp;
106     }
107 
108     public void setIncludeParams(String name) {
109         includeParams = name;
110     }
111 
112     public void setAction(String action) {
113         this.action = action;
114     }
115 
116     public void setNamespace(String namespace) {
117         this.namespace = namespace;
118     }
119 
120     public void setMethod(String method) {
121         this.method = method;
122     }
123 
124     public void setScheme(String scheme) {
125         this.scheme = scheme;
126     }
127 
128     public void setValue(String value) {
129         this.value = value;
130     }
131 
132     public void setPortletMode(String portletMode) {
133         this.portletMode = portletMode;
134     }
135 
136     public void setPortletUrlType(String portletUrlType) {
137         this.portletUrlType = portletUrlType;
138     }
139 
140     public void setWindowState(String windowState) {
141         this.windowState = windowState;
142     }
143 
144     public void setAnchor(String anchor) {
145         this.anchor = anchor;
146     }
147 
148     public void setForceAddSchemeHostAndPort(String forceAddSchemeHostAndPort) {
149         this.forceAddSchemeHostAndPort = forceAddSchemeHostAndPort;
150     }
151     //a标签只需要重写一个方法就行
152     @Override
153     public int doEndTag() throws JspException {
154         if(namespace==null||"/".equals(namespace)){
155             namespace="";
156         }
157         if(action==null){
158             action="";
159         }else{
160             if(action.endsWith(".action")){
161                 action=action.substring(0, action.indexOf("."));
162             }
163         }
164         boolean result=ValidateUtils.hasRight(namespace, action, (HttpServletRequest)pageContext.getRequest(), null);
165 //        System.out.println("即将访问"+namespace+action);
166         if(result==true){
167 //            System.out.println("有权限,即将放行!");
168             return super.doEndTag();
169         }else{
170 //            System.out.println("没有权限,即将跳过标签体!");
171             return SKIP_BODY;
172         }
173     }
174 }
org.apache.struts2.views.jsp.ui.AnchorTag.java

相关文章:

  • 2021-05-29
  • 2022-12-23
  • 2021-11-13
  • 2022-12-23
  • 2021-05-18
  • 2021-08-05
  • 2021-06-04
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-06-19
  • 2022-12-23
  • 2021-05-30
  • 2021-09-26
相关资源
相似解决方案