【问题标题】:Using Interceptor to validate user access privilege使用拦截器验证用户访问权限
【发布时间】:2014-12-30 08:21:48
【问题描述】:

我正在尝试使用Interceptor 来限制用户执行某些操作。

ContainsKeyInterceptor:

public class ContainsKeyInterceptor extends AbstractInterceptor implements SessionAware {
    private static final long serialVersionUID = 1L;

    private Map<String, Object> session;

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        if(session == null) {
            System.out.println("session is null");
        }

        if(session.containsKey("currentId")) {
            return "index";
        }

        String result = actionInvocation.invoke();

        return result;
    }

    @Override
    public void setSession(Map<String, Object> session) {
        this.session = session;
    }
}

如果在session 中找到currentId,则应该将用户重定向到索引页面。

但是,我得到一个 NullPointerException,说 session 为空,由 if-check 验证。

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="false" />

    <!-- actions available to guests -->
    <package name="guest" extends="struts-default">
        <interceptors>
            <interceptor name="containskeyinterceptor" class="com.mypackage.interceptor.ContainsKeyInterceptor" />
        </interceptors>

        <action name="index" class="com.mypackage.action.IndexAction">
            <interceptor-ref name="containskeyinterceptor" />
            <result type="redirect">/index.jsp</result>
            <result name="index" type="redirect">/index.jsp</result>
        </action>

        <action name="login" class="com.mypackage.action.LoginAction">
            <interceptor-ref name="containskeyinterceptor" />
            <result type="redirect">/index.jsp</result>
            <result name="input">/login.jsp</result>
            <result name="index" type="redirect">/index.jsp</result>
        </action>       
    </package>

    <!-- actions available to members -->
    <package name="member" extends="struts-default">
        <action name="logout" class="com.mypackage.action.LogoutAction">
            <result type="redirectAction">
                <param name="actionName">index</param>
            </result>
        </action>
    </package>
</struts>

为什么session 为空以及如何解决?

This 是我使用的参考。)

【问题讨论】:

    标签: java struts2 interceptor


    【解决方案1】:

    Struts Session 只是一个 Map&lt;String,Object&gt; 包装底层 HttpSession

    在实现 SessionAware 接口 is the correct way to get it in an Action 时,如果你想从 Interceptor 中获取它,你需要执行以下操作:

    获取 Struts Session Map

    @Override
    public String intercept(ActionInvocation ai) throws Exception {
        final ActionContext context = ai.getInvocationContext();
    
        // Struts Session
        Map<String, Object> session = context.getSession();
    

    获取真正的HttpSession对象

    @Override
    public String intercept(ActionInvocation ai) throws Exception {
        final ActionContext context = ai.getInvocationContext();
    
        HttpServletRequest request = (HttpServletRequest)context.get(StrutsStatics.HTTP_REQUEST);
    
        // Http Session
        HttpSession session = request.getSession();
    

    也就是说,您在操作中没有获得会话(也没有任何其他参数、对象等)的原因是您犯了一个常见错误:只应用一个拦截器(你的)而不是应用整个拦截器堆栈(应该包含你的):

    你可以在每个动作中定义两次:

    <action name="login" class="ph.edu.iacademy.action.LoginAction">
        <interceptor-ref name="defaultStack" /> <!-- this is missing -->
        <interceptor-ref name="containskeyinterceptor" />
    

    或者,更好的是,在自定义堆栈中定义一次,并始终使用堆栈:

    <interceptors>
        <interceptor-stack name="yourStack">                
           <interceptor-ref name="defaultStack"/>
           <interceptor-ref name="containskeyinterceptor"/>
        </interceptor-stack>
    </interceptors>
    
    <action name="login" class="ph.edu.iacademy.action.LoginAction">
        <interceptor-ref name="yourStack" />
    

    并最终使用 default-interceptor-ref 定义它,以避免为该包的每个操作配置编写它:

    <default-interceptor-ref name="yourStack"/>
    
    <action name="login" class="ph.edu.iacademy.action.LoginAction">
    

    【讨论】:

    • 嗨 Andrea,我什么时候可以得到 Session Map,什么时候可以得到真正的 HttpSession 对象?
    • 通常你只需要地图。
    • 谢谢,成功了!我使用了 Session Map 和“定义两次”方法,现在我将尝试使用 &lt;interceptor-stack&gt;。赞成并标记为接受的答案。
    【解决方案2】:

    基于this,我认为拦截器本身不能/需要知道会话。

    您可以这样访问此属性:

    final ActionContext context = actionInvocation.getInvocationContext();  
    this.session = context.getSession();  
    

    可能有一种方法可以自动获取此设置,我对 struts2 不太熟悉,但可能是 sessionaware 仅适用于特定的对象子集,并且此拦截器由于某种原因不是其中之一. (不被扫描,被排除在扫描之外,类型错误)

    【讨论】:

    • 嗨,我删除了拦截器中的所有SessionAware 引用,并将您的代码放在intercept() 方法中。 session 不再为空,但现在我在 IndexAction 类中遇到了NullPointerException(第 9 行 - 会话为空)。
    • 这回答了第一个问题,+1
    • 对了,为什么一定要final呢?
    • 不一定是这样,但这是一个很好的约定。任何不打算更改的变量都应声明为 final。基本上,如果您没有为变量定义 setter,并且子类不打算更改它,那么将其声明为 final。我特别为任何使用初始化程序设置的变量而不是像这种情况下通过构造函数设置的变量这样做。
    猜你喜欢
    • 2015-12-25
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2014-03-20
    • 1970-01-01
    • 2017-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多