如何在Guice中使用@SessionScoped

5

你好
我目前正在使用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);
    }
}

这段代码不起作用,我的Identity的uid始终为“null”。

让我们来看看问题:

a - 首先,为什么我的代码不起作用?
b - @SessionScoped是否等同于将对象设置在HttpSession中?
c - 如何使(http)会话中的Identity对象无效(仅限它)?
d - 一般来说,我们在什么情况下需要使用@SessionScoped?

感谢您的阅读,
期待您的答案。


如何从Servlet访问LoginAction类? - Daniel
我有一个FrontServlet,它通过“injector.getInstance(LoginAction.class);”进行注入。 - Pierre
1个回答

9
[a] 你正在将一个新的 Identity 实例分配给 LoginAction 中的一个局部变量,而不是替换由 Guice 管理的实例。您可以通过填充由 Guice 管理的现有 Identity 实例上的 uidname 字段来解决问题。
例如,您可以这样做:
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 服务来管理会话用户的 Identity,并确保在 Identity 实例上同步。这样,如果用户快速发出两个请求,您就不会遇到并发问题。
  • 优先注入 Provider 而不是注入 Injector(示例在此处),以将类与 Guice 解耦。
  • 将依赖项注入到类的构造函数,而不是注入字段。这样可以更轻松地进行测试(通过在测试中提供模拟/存根依赖项)。

我该如何获取现有的实例?我认为“injector.getInstance()”就可以完成这项工作。 - Pierre
太好了,它可运行!谢谢!(回复 [a] 完成!)更干净的方式呢? :) - Pierre
很高兴听到这个好消息 :)。我已经回答了你其他问题的一些答案。 - Daniel
@Daniel:像你说的那样,我使用 Provider 而非滥用 Injector,现在可以很好地工作了。另外,我尝试过实现“IdentityManager”,但一直没有成功,你能给我更多线索吗? - Pierre
一个简单的实现可以只是一个带有身份字段、getter和setter的@SessionScoped bean。一旦从您的Authentication类获取了Identity实例,您就可以将其设置在IdentityManager中以便以后访问。 - Daniel
好的,我会做的。谢谢你的帮助! - Pierre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接