如何在Guice中使用@SessionScoped

时间:2011-04-25 09:53:55

标签: java authentication guice session-scope

您好
我目前正在玩Guice和@SessionScoped。为了更有意义,我决定构建一个(非常简单的)身份验证过程。

下面,我将解释我所做的每一步。然后我会问你一些问题。

[1] 我创建了一个代表一个人(访客或用户)的Identity类:

@SessionScoped
public class Identity implements Serializable
{
    private String uid;
    private String name;

    public boolean isAuthenticate()
    {
        return uid != null;
    }

    public void logout()
    {
        this.uid = null;
    }

    /*Setters-Getters*/
}

[2] 接下来,我创建了一个登录用户的身份验证类:

public class Authentication
{
    @Override
    public Identity authenticate(String login, String password)
    {
        /*some code*/

        Identity identity = new Identity();
        identity.setUid(user.getId());
        return identity;
    }
}

[3] 然后,在我的Servlet中,我登录用户:

@RequestScoped
public class LoginAction
{
    @Inject
    Injector injector;

    protected void login(HttpServletRequest req, HttpServletResponse resp)
    {
            Identity identity = injector.getInstance(Identity.class);
            Authentication auth = new Authentication();
            identity = auth.authenticate("login","password");
    }
}

[4] 最后,我创建了一个过滤器,告诉我用户是否经过身份验证:

@Singleton
public class SecurityFilter implements Filter
{
    @Inject
    private Injector injector;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
    {
        Identity identity = injector.getInstance(Identity.class);

        if(identity.isAuthenticate())
        {
            System.err.println("USER");
        }
        else
        {
            System.err.println("GUEST");
        }

        chain.doFilter(request, response);
    }
}

嗯,这段代码不起作用。我的身份的uid总是“空”。

让我们回答问题:

a - 首先,为什么我的代码不起作用? b - @SessionScoped是否相当于在HttpSession中设置对象?
c - 如何在(http)会话中使Identity对象(仅限于它)无效? d - 通常,在哪种情况下我们必须使用@SessionScoped?

感谢您的阅读,
等你的回答。

1 个答案:

答案 0 :(得分:9)

[a]您将Identity的新实例分配给LoginAction中的本地变量,而不是替换Guice管理的实例。您可以通过填充Guice管理的现有uid实例上的nameIdentity字段来解决问题。

例如,而不是

identity = auth.authenticate("login","password"); 
你可以说:

Identity identity = injector.getInstance(Identity.class);
Authentication auth = new Authentication();
Identity authenticated = auth.authenticate("login","password");
identity.setUid(authenticated.getUid());
identity.setName(authenticated.getName());

有更简洁的方法可以做到这一点,但你明白了。

[b] / [d]这是正确的:@SessionScoped相当于在HttpSession中设置变量,这就是您要使用它的情况。对于需要在会话中唯一的对象,您需要它,但需要为每个请求提供。

[c]我不太清楚你的意思,但是如果你想根据用户是否登录而重定向到应用程序的不同位置,你的过滤器设计是一种常见的方法。

您可以进行一些改进:

  • 拥有管理会话用户SessionScoped的{​​{1}}服务,并确保它在Identity实例上同步。这样,如果用户快速连续发出两个请求,您将不会遇到并发问题。
  • 首选注入Identity而不是注入Provider(示例here)以将您的类与Guice分离。
  • Inject dependencies into your classes' constructors,而不是注入字段。这样可以更容易地进行测试(通过在测试中提供模拟/存根依赖性)。