歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Struts1運用Java注解實現簡單的權限控制

看到標題,不要以為看錯,沒錯,就是Struts1!
對於一個目前只能編碼的人來說,在公司做項目,技術框架基本不會是你自己決定的。唉,最近的一個項目,他們要求就是要用Struts1,對於我剛接觸Struts就是版本2的人來說,Struts1幾乎就沒再關注過,而且大家也應該都了解Struts1與Struts2的區別到底有多大。一把辛酸淚,就不多說了。
閒話不說,先說下需求。
由於項目規模不大,要求加入簡單的權限管理,要求是,
1.不同權限角色進入系統後,顯示對應權限的菜單項;
2.後台的Action請求加入權限控制
數據表有客戶提供,用戶表裡只是簡單的放入了role字段以區分用戶角色。取值為0-5。
前台的菜單項顯示與隱藏的控制使用js動態生成,這裡主要講後台的實現,所以前台就簡單描述一下。實現方式是定義一個多維數組,存入需要的一級和二級菜單信息,然後解析數組,生成自己想要的格式,利用js拼成html標簽。
重點說下後台的實現。後台的實現,一開始我也沒想到使用Java的注解,看到這個方法, http://www.linuxidc.com/Linux/2016-12/138293.htm 使用struts1+注解做權限管理。思路簡單來說就是,在調用每個Action之前判斷權限,有則放行,無則攔截。
對於Struts1來說,工作流程是:ActionSerlvet接收客戶Http請求,使用ActionForm Bean自動填充客戶送來的表單數據到ActionForm Bean對象中;根據配置信息(struts_config.xml)將請求分發給相應的Action對象,Action對象調用execute()方法處理請求(根據JavaBean和ActionForm取得業務邏輯和表單數據),並反回ActionForward對象給ActionSerlvet對象,根據ActionForward對象的信息(目標頁面),ActionServlet再次將Http請求導航到目標頁面,並發送到客戶端。
因此,判斷出請求處理器ActionSerlvet的哪個方法調了action,就是關鍵所在了。通過調試斷點放在ActionServlet的dopost方法上,發現是processActionPerform調用的action,剩下的就是重寫這個方法就好了。當然要記得在xml文件中配置controller標簽,指定用自己的請求處理器。
下面通過代碼具體實現來說明。
首先,定義Java注解類,Java注解的相關知識這裡不是重點,也不多提。
定義一個注解,即一個權限的數組。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 權限控制,注解類
 * 生成策略:運行時 
 * 注解位置:方法 
 * @author wangxx
 *
 */

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface <span >SystemPrivilegeAnnotation </span>
{
    String[] privilegeValue();// 權限值
}

然後,根據前面的分析,重寫RequestProcessor的processActionPerform方法。根據注釋應該也能看的明白。

import java.io.IOException;
import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.RequestProcessor;
import org.apache.struts.actions.DispatchAction;
import org.apache.struts.actions.MappingDispatchAction;

/**
 * 權限管理器
 * 
 * 
 * 步驟:
 * 1、要判斷調用的是action的哪個方法,通過反射
 *  一般action有三種方式:
 *      第一,直接繼承Action的action,那麼方法名就是“execute”;
 *      第二,繼承DispatchAction的action,那麼方法名就是request域中對應的mapping中的parameter;
 *      第三,繼承MappingDispatchAction的action,那麼方法名就是mapping中的parameter
 *  通過反射得到調用action的哪個方法
 * 2、判斷調用的方法上面有沒有注解,也就是調用這個方法需不需要權限,
 *  不需要,調用超類的processActionPerform;
 *  需要的話,檢查用戶的權限是否contains這個權限,是就放行,不是不放行
 * 
 * @author wangxx
 *
 */
public class PrivilegController extends RequestProcessor {

    /*
     * 斷點在ActionServlet的dopost方法上, 發現是processActionPerform調用的action
     * 
     * @see
     */
    @Override
    protected ActionForward processActionPerform(HttpServletRequest request,
            HttpServletResponse response, Action action, ActionForm form,
            ActionMapping mapping) throws IOException, ServletException {

        //判斷權限
        if (!systemPrivilege(request, action, mapping)) {
            ActionMessages messages = new ActionMessages();
            messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
                    "error.no.permission"));
            saveErrors(request, messages);
            //request.setAttribute("org.apache.struts.action.ERROR", "您沒有權限進行當前操作!");
            //重定向到login
            // request.setAttribute("toUrl", SiteURL.getUrlByKey("logon"));
            return mapping.findForward("nonpermission");
        }
        return super.processActionPerform(request, response, action, form,
                mapping);
    }

    // 權限判斷方法,返回true說明當前用戶有權限調用當前方法
    private boolean systemPrivilege(HttpServletRequest request, Action action,
            ActionMapping mapping) {
        // 拿到方法的名字
        String currentMethodName = getCurrentMethodName(request, action,
                mapping);
        // 拿出方法中的注解信息
        SystemPrivilegeAnnotation systemPrivilegeAnnotation = getMethodSystemPrivilegeAnnotation(
                action, currentMethodName);
        // 如果注解信息為空說明當前方法不需要任何權限
        if (systemPrivilegeAnnotation == null) {
            return true;
        }

        //有注解,即需要權限
        // 根據注解信息建立權限對象,即當前方法所需權限
        String[] privilegeValue = systemPrivilegeAnnotation.privilegeValue();
        // 拿出當前用戶--也可以存在session,總之這一步是為了取得當前登錄者的信息
        UserInfo userInfo = (UserInfo) request.getSession().getAttribute(
                ConstApp.SESSION_USERINFO);
        String userRole = userInfo.getUserRole();

        //循環,將當前用戶的所有權限逐個與當前方法所需權限相比較
        for (String role : privilegeValue) {
            if(role.equals(userRole)){
                return true;
            }
        }

        return false;
    }

    /**
     * 取得當前action方法的名字
     * 
     * @param request
     * @param action
     * @param mapping
     * @return
     */
    private String getCurrentMethodName(HttpServletRequest request,
            Action action, ActionMapping mapping) {
        // 繼承DispatchAction的action,那麼方法名就是request域中對應的mapping中的parameter
        if (DispatchAction.class.isAssignableFrom(action.getClass())) {
            return request.getParameter(mapping.getParameter());
        }
        // 繼承MappingDispatchAction的action,那麼方法名就是mapping中的parameter
        if (MappingDispatchAction.class.isAssignableFrom(action.getClass())) {
            return mapping.getParameter();
        }
        // 直接繼承Action的action,那麼方法名就是“execute”;
        return "execute";
    }

    /**
     * 通過反射得到action方法的注解信息
     * @param action
     * @param methodName
     * @return
     */
    private SystemPrivilegeAnnotation getMethodSystemPrivilegeAnnotation(
            Action action, String methodName) {
        try {
            // 第二個參數是所求方法的參數列表
            Method method = action.getClass()
                .getMethod(methodName,new Class[] { ActionMapping.class,
                        ActionForm.class, HttpServletRequest.class,HttpServletResponse.class });
            if (method != null) {
                if (method.isAnnotationPresent(SystemPrivilegeAnnotation.class)) {
                    return method.getAnnotation(SystemPrivilegeAnnotation.class);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 顯示錯誤消息
     * @param request
     * @param errors
     */
    protected void saveErrors(HttpServletRequest request, ActionMessages errors)
    {
        if(errors == null || errors.isEmpty())
        {
            request.removeAttribute("org.apache.struts.action.ERROR");
            return;
        } else
        {
            request.setAttribute("org.apache.struts.action.ERROR", errors);
            return;
        }
    }

}

第三,別忘了在配置文件struts-config.xml添加controller。


<controller processorClass="common.PrivilegController" contentType="text/html;chatset=utf-8">
</controller>  

最後,在需要權限的Action中添加注解就可以。privilegeValue中設置權限值即可。

/**
 * 用戶密碼修改初期化
 * 
 * @author wang
 *
 */
public class ChangePasswordAction extends Action{

    /*
     * 用戶密碼修改初期化
     * 
     * @see
     */
    @SystemPrivilegeAnnotation(privilegeValue = {"0","1","2","3","4"})
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        。。。。。
    }
}

至此,Struts1利用Java注解進行權限控制就基本完成了,思路基本就是如此,方法不一定最好,但是實現需求就好!
最後,這只是在工作中遇到的一個小問題,不一定具有普遍性,自己能力也有限,目前實現的方式就是這樣,如果想到好的會做補充。

Copyright © Linux教程網 All Rights Reserved