Jetty 找不到登录名.jsp使用泽西-吉斯-四郎堆栈时



(更新2013年1月2日)我现在已经添加了所有的代码加上一个pom.xml到github https://github.com/AndyWi/GuiceJerseyJettyShiroExample(最后更新)

我试图使用Shiro添加基于表单的身份验证到我的简单应用程序。该应用程序使用Guice 3.0, Jersey 1.16和Shiro 1.2.1,运行在嵌入式Jetty 9.0.0.M4上。

我的问题是(据我所知)Shiro需要通过Guice提供login.jsp,然后添加到Shiro的过滤器链中。但是,当我这样做时,Jetty找不到login.jsp。当我从Guice过滤器中排除login.jsp时,Jetty可以找到这个jsp,但是Shiro无法使用它,因此身份验证不起作用。

因此,在我的引导代码中,我使用这一行将login.jsp添加到Guice Filter中:
webAppContext.addFilter(GuiceFilter.class, "/login.jsp", null);

在我的ShiroWebModule中,我像这样添加login.jsp:

addFilterChain("/login.jsp", AUTHC);

我花了很长时间寻找这个问题的答案,没有任何暗示,其他人也有同样的问题-这意味着我显然做了一些非常简单的错误!但我不知道是什么。如果有人能帮我解决这个问题,我将非常感激。

我已经将我的项目简化为一个小示例来演示这个问题。所有这些应该做的就是接受/api/uuid的rest url,将用户重定向到login.jsp,接受任何用户名/密码组合进行身份验证,然后从/api/uuid服务返回一个新的uuid;用户还应该保持登录状态以备将来的请求。下面是完整的代码,希望它能帮助人们发现问题:

引导:

package eg.guicejerseyjettyshiro;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.webapp.WebAppContext;
import com.google.inject.servlet.GuiceFilter;
import eg.guicejerseyjettyshiro.modules.EgGuiceServletContextListener;
public class Bootstrap {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8081);
        WebAppContext webAppContext = new WebAppContext();
        webAppContext.setContextPath("/");
        webAppContext.setResourceBase("src/main/webapp/");
        webAppContext.setParentLoaderPriority(true);
        webAppContext.addEventListener(new EgGuiceServletContextListener());
        webAppContext.addFilter(GuiceFilter.class, "/api/*", null);
        // **** Shiro needs login.jsp to go through the GuiceFilter,
        // but Jetty can't find the jsp when this happens. Commenting
        // out this line lets Jetty find the jsp, but Shiro can't see it:
        webAppContext.addFilter(GuiceFilter.class, "/login.jsp", null);
        webAppContext.addServlet(DefaultServlet.class, "/");
        server.setHandler(webAppContext);
        server.start();
        server.join();
    }
}

EgGuiceServletContextListener:

package eg.guicejerseyjettyshiro.modules;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
public class EgGuiceServletContextListener extends GuiceServletContextListener {
    private ServletContext servletContext;
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        this.servletContext = servletContextEvent.getServletContext();
        super.contextInitialized(servletContextEvent);
    }
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(
                new EgJerseyServletModule(),
                new EgShiroWebModule(this.servletContext));
    }
}

EgJerseyServletModule:

package eg.guicejerseyjettyshiro.modules;
import org.apache.shiro.guice.web.GuiceShiroFilter;
import com.sun.jersey.guice.JerseyServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import eg.guicejerseyjettyshiro.dao.UuidDao;
import eg.guicejerseyjettyshiro.services.UuidService;
public class EgJerseyServletModule extends JerseyServletModule {
    @Override
    protected void configureServlets() {
        bindings();
        filters();
    }
    private void bindings() {
        bind(UuidDao.class);
        bind(UuidService.class);
    }
    private void filters() {
        filter("/*").through(GuiceShiroFilter.class);
        filter("/*").through(GuiceContainer.class);
    }
}

EgShiroWebModule:

package eg.guicejerseyjettyshiro.modules;
import javax.servlet.ServletContext;
import org.apache.shiro.guice.web.ShiroWebModule;
import com.google.inject.name.Names;
import eg.guicejerseyjettyshiro.realms.EgAuthorizingRealm;
public class EgShiroWebModule extends ShiroWebModule {
    public EgShiroWebModule(ServletContext servletContext) {
        super(servletContext);
    }
    @Override
    protected void configureShiroWeb() {
        bindConstant().annotatedWith(Names.named("shiro.globalSessionTimeout")).to(30000L);
        bindRealm().to(EgAuthorizingRealm.class).asEagerSingleton();
        addFilterChain("/login.jsp", AUTHC);
        addFilterChain("/api/*", AUTHC);
    }
}

EgAuthorizingRealm:

package eg.guicejerseyjettyshiro.realms;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class EgAuthorizingRealm extends AuthorizingRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        System.out.println("In EgAuthorizingRealm.doGetAuthenticationInfo for: " + upToken.getUsername() + "/" + new String(upToken.getPassword()) + " - remember=" + upToken.isRememberMe());
        return new SimpleAuthenticationInfo(upToken.getUsername(), upToken.getPassword(), getName());
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
        System.out.println("In EgAuthorizingRealm.doGetAuthorizationInfo");
        // Doing nothing just now
        return null;
    }
}

UuidService:

package eg.guicejerseyjettyshiro.services;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import eg.guicejerseyjettyshiro.dao.UuidDao;
@Path("/api/uuid")
@Produces({MediaType.APPLICATION_XML})
public class UuidService {
    private final UuidDao uuidDao;
    @Inject
    public UuidService(UuidDao uuidDao) {
        this.uuidDao = uuidDao;
    }
    @GET
    public String get() {
        Subject currentUser = SecurityUtils.getSubject();
        System.out.println("UuidService current user: " + currentUser.getPrincipal().toString());
        return "<uuid>" + this.uuidDao.generateUuid().toString() + "</uuid>";
    }
}

UuidDao:

package eg.guicejerseyjettyshiro.dao;
import java.util.UUID;
public class UuidDao {
    public UUID generateUuid() {
        return UUID.randomUUID();
    }
}
login . jsp

:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Please Login</title>
</head>
<body>
<form name="loginForm" action="" method="post">
<table align="left" border="0" cellspacing="0" cellpadding="3">
    <tr>
        <td>Username:</td>
        <td><input type="text" name="username" maxlength="30"></td>
    </tr>
    <tr>
        <td>Password:</td>
        <td><input type="password" name="password" maxlength="30"></td>
    </tr>
    <tr>
        <td colspan="2" align="left"><input type="checkbox" name="rememberMe"><font size="2">Remember Me</font></td>
    </tr>
    <tr>
        <td colspan="2" align="right"><input type="submit" name="submit" value="Login"></td>
    </tr>
</table> 
</form>
</body>
</html>

好的,我想就这些了。我知道这篇文章很长,所以非常感谢你读到这里。这已经把我逼疯了,所以任何你能给我的帮助将是非常感激的!

谢谢,安迪。

这个问题已经在Shiro用户论坛上得到了Milan Baran的回答。github仓库已经更新,这里有一个快速的摘要,以防有人感兴趣:

在Bootstrap类中,我们只需要为/*添加一个guiceffilter,并且根本不需要默认服务器。这就变成了:

public static void main(String[] args) throws Exception {
    Server server = new Server(8081);
    WebAppContext webAppContext = new WebAppContext();
    webAppContext.setContextPath("/");
    webAppContext.setResourceBase("src/main/webapp/");
    webAppContext.setParentLoaderPriority(true);
    webAppContext.addEventListener(new EgGuiceServletContextListener());
    webAppContext.addFilter(GuiceFilter.class, "/*", null);
    server.setHandler(webAppContext);
    server.start();
    server.join();
}

然后我们需要更新jersey servlet模块以绑定DefaultServlet和GuiceContainer,并通过GuiceContainer将过滤器更改为通过/api而不是/*,如下所示:

public class EgJerseyServletModule extends JerseyServletModule {
@Override
protected void configureServlets() {
    bindings();
    filters();
}
private void bindings() {
    bind(UuidDao.class);
    bind(UuidService.class);
    bind(DefaultServlet.class).asEagerSingleton();
    bind(GuiceContainer.class).asEagerSingleton();
    serve("/*").with(DefaultServlet.class);
}
private void filters() {
    filter("/*").through(GuiceShiroFilter.class);
    filter("/api/*").through(GuiceContainer.class);
}
}

感谢大家的帮助!安迪。

最新更新