(2013年1月2日更新)我现在已经将所有代码和一个pom.xml添加到https://github.com/AndyWi/GuiceJerseyJettyShiroExample的github中(更新结束)
我正在尝试使用Shiro将基于表单的身份验证添加到我的简单应用程序中。该应用程序使用Guice 3.0、Jersey 1.16和Shiro 1.2.1,运行在嵌入式Jetty 9.0.0.M4上。
我的问题是(据我所知)Shiro需要login.jsp通过Guice可用,然后添加到Shiro的过滤器链中。但是,当我这样做时,Jetty找不到login.jsp.当我从Guice过滤器中排除login.jsp时,Jetty可以找到jsp,但是Shiro不可用,因此身份验证不起作用。
因此,在我的引导代码中,我使用此行将 login.jsp 添加到 Guice 筛选器:
webAppContext.addFilter(GuiceFilter.class, "/login.jsp", null);
在我的ShiroWebModule中,我添加了登录名.jsp如下所示:
addFilterChain("/login.jsp", AUTHC);
我花了很长时间寻找这个问题的答案,却没有任何迹象表明其他人也有同样的问题-这意味着我显然在做一些非常简单的错误!但我不知道是什么。如果有人能帮我度过难关,我将非常感激。
我已经将我的项目简化为一个小例子来演示这个问题。所有这些应该做的就是接受/api/uuid的rest url,将用户重定向到登录。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();
}
}
登录.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用户论坛上的米兰·巴兰。github存储库已经更新,如果有人感兴趣,这里有一个快速摘要:
在 Bootstrap 类中,我们只需要为 /* 添加一个 GuiceFilter,并且根本不需要默认服务器。所以,这变成了:
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);
}
}
感谢大家的帮助!安迪。
类似于另一个问题(参见过滤静态内容Jersey),我想从Jetty提供静态内容。在浩瀚的互联网上散布着几个类似的问题,但大多数都不涉及Guice,而那些涉及Guice的问题已经完全过时了。 我有一个现有的服务,使用泽西(1.12)和Guice(3)与以下: < code>MyGuiceConfig看起来像这样: 当我使用 时,我的服务按预期工作。但是,任何对静态内容的请求都会产生404。 如何在不
当我试图上传文件到泽西岛时,我发现下面有一些异常,请帮助我解决。谢谢 html文档:- 阿贾克斯:- Java代码:- 例外情况:- 2015年6月17日下午7:55:34组织。阿帕奇。卡塔琳娜。果心StandardWrapperValve调用 请求头:-
问题内容: 我的问题是:为什么在创建部署在某种servlet容器(如jetty或tomcat)上的应用程序时执行JavaSE应用程序和ServletModule时需要创建AbstractModule?它们之间有什么区别? 我需要将Jersey与Guice集成在一起。是否需要注册Guice的存在才能以某种方式使用它?我是否可以仅启用注入并在我想要的任何地方(常规类,过滤器,处理程序,服务,DAO等)
我对web服务非常陌生,所以我从基本示例开始。这与文件上传有关。我正在为非maven开发人员使用最新(2.17)版本的Jersey捆绑包。它指出: 捆绑包包含JAX-RS 2.0 API jar、所有核心泽西模块jar以及所有必需的第3方依赖项 .问题是我不能编译这部分: Jersey 2.17捆绑包中似乎不存在FormDataParam,尽管docs表示存在。2.17捆绑包是否不完整?如何解决此
我有一个奇怪的问题,我完全不明白,泽西岛2.6。 我无法解释为什么,但其中一个查询参数使泽西岛抛出模型验证异常 查询参数“一些价值”使球衣投掷: 如果我用String代替SomeValueDTO,一切都没问题。SomeValueDTO是一个非常经典的POJO,带有一个空的构造函数和getter/setter。 如果有人有伊迪亚!!
我正在创建一个在Karaf中作为OSGi容器运行的应用程序,并使用OSGi HTTP服务和Jersey来公开REST APIs。我需要添加SAML2身份验证和基于权限的授权。为此,我想在Shiro中使用基于注释的方法,因为spring似乎正在远离OSGi。我的问题: 带有SAML罐子的Shiro是否适合OSGi环境? 我想使用WSO2作为身份提供者。Shiro和WSO2一起工作有任何警告吗? 对于