5


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

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

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

@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 始终为“null”。

让我们来提问:

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

感谢您的阅读,
等待您的答复。

4

1 回答 1

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管理会话用户的服务Identity,并确保它在Identity实例上同步。这样,如果用户快速连续发出两个请求,您将不会遇到并发问题。
  • 更喜欢注入Providers 而不是注入(此处Injector的示例)以将您的类与 Guice 分离。
  • 将依赖项注入类的构造函数,而不是注入字段。这使得测试更容易(通过在测试中提供模拟/存根依赖项)。
于 2011-04-25T10:49:29.457 回答