我正在使用Guice + Jersey + Shiro通过REST API登录,然后使用我登录的相同HTTP会话,并让我的权限适用于该资源。
以下是我的代码。
首先,我的servlet配置: -
public class ServletConfiguration extends GuiceServletContextListener
{
private ServletContext mServletContext;
@Override
public void contextInitialized(ServletContextEvent inEvent)
{
mServletContext = inEvent.getServletContext();
super.contextInitialized(inEvent);
}
@Override
protected Injector getInjector()
{
mServletContext.addListener(new au.com.tt.agora.configuration.CbiCleanupHttpSessionListener());
return Guice.createInjector(new JerseyServletModule() {
@Override
protected void configureServlets()
{
install(new TTShiroWebModule(mServletContext));
install(new ShiroAopModule());
filter("/*").through(GuiceShiroFilter.class);
bind(ShiroLoginResource.class);
bind(ShiroResource.class);
filter("/*").through(GuiceContainer.class);
}
});
}
}
现在,这是我的测试领域: -
包au.com.tt.agora.configuration.shiro;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class TestRealm extends AuthorizingRealm
{
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken inToken) throws AuthenticationException
{
UsernamePasswordToken upToken = (UsernamePasswordToken) inToken;
if (upToken.getUsername().equals("Kamal") || upToken.getUsername().equals("NotKamal"))
return new SimpleAuthenticationInfo(upToken.getUsername(), upToken.getPassword(), getName());
return null;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection inPrincipals)
{
String username = (String) inPrincipals.fromRealm(getName()).iterator().next();
SimpleAuthorizationInfo authzInfo = new SimpleAuthorizationInfo();
if (username.equals("Kamal"))
{
authzInfo.addStringPermission("PRODMA:READ:AU");
authzInfo.addStringPermission("PRODMA:WRITE:KB");
authzInfo.addStringPermission("SUPPMA:READ:KB");
}
else
{
authzInfo.addStringPermission("PRODMA:READ:AU");
authzInfo.addStringPermission("PRODMA:WRITE:KB");
}
return authzInfo;
}
}
这是网络模块
package au.com.tt.agora.configuration.shiro;
import javax.servlet.ServletContext;
import org.apache.shiro.guice.web.ShiroWebModule;
public class TTShiroWebModule extends ShiroWebModule
{
public TTShiroWebModule(ServletContext inServletContext)
{
super(inServletContext);
}
@SuppressWarnings("unchecked")
@Override
protected void configureShiroWeb()
{
bindRealm().to(TestRealm.class);
addFilterChain("**/shiroResource/*", ANON);
}
}
以下是我用于登录的资源: -
package au.com.tt.agora.configuration.jaxrs.resources;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import com.google.inject.Inject;
import au.com.tt.agora.configuration.option.ClientProvider;
import au.com.tt.agora.configuration.option.ConfigurationProvider;
import au.com.tt.agora.login.web.request.LoginRequest;
import au.com.tt.agora.login.web.request.LoginResponse;
import au.com.tt.agora.login.web.service.LoginHandler;
import au.com.tt.calypso.cbi.CalypsoException;
@Path("/{client}/shiroLogin")
public class ShiroLoginResource
{
private static final String ROUTING_TOKEN_HEADER = "proxy-jroute";
@POST
@Path("/standard")
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_JSON)
public String login(@Context HttpServletRequest inServletRequest) throws CalypsoException
{
Subject subject = SecurityUtils.getSubject();
subject.login(new UsernamePasswordToken("Kamal", "Password", false));
return getSessionIdWithRouting(inServletRequest);
}
private String getSessionIdWithRouting(HttpServletRequest inRequest)
{
String sessionId = inRequest.getSession().getId();
return(sessionId);
}
}
这是我正在调用的资源: -
package au.com.tt.agora.configuration.jaxrs.resources;
import javax.servlet.http.HttpSession;
import javax.ws.rs.POST;
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.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Inject;
@Path("/{client}/shiroResource")
public class ShiroResource
{
private static final Logger LOG = LoggerFactory.getLogger(ShiroResource.class);
@Inject
public ShiroResource()
{
}
@POST
@Path("requiresProdma.do")
@Produces(MediaType.TEXT_PLAIN)
@RequiresPermissions({ "PRODMA:*:*" })
public String prodmaRequired()
{
return "Success";
}
@POST
@Path("requiresSuppma.do")
@Produces(MediaType.TEXT_PLAIN)
@RequiresPermissions({ "SUPPMA:*:*" })
public String suppmaRequired()
{
Subject subject = SecurityUtils.getSubject();
subject.getPrincipal();
return "Success";
}
}
如果我将断点放入suppmaRequired并调用此资源,我可以看到该主题未经过身份验证。
我对Shiro如何运作的理解显然是错误的,但我不知道我在做什么。有人能指出我正确的方向吗?
不确定它是否有所作为,但我使用URL重写来访问网络会话。
基本上,我使用fetch API来测试它。这是一个例子: -
fetch("http://localhost/app/tt/shiroLogin/standard", {
method: "POST",
headers: {
"Content-Type" : "application/json"
} ,
body: '{"username":"myName","password":"myPassword"}'
})
.then(function(res) {
return res.text();
})
.then(function(sessionId) {
return fetch("http://localhost/app/tt/shiroResource/requiresSuppma.do;JSESSIONID=" + sessionId,
{
method: "POST"
});
})
.then(function(res) {
return res.text();
})
.then(function(res) {
console.log(res);
});
我也在部署到glassfish。
答案 0 :(得分:0)
好的,这最终不是Shiro的问题。我正在使用从ShiroLoginResource到ShiroResource的两个不同的会话。
我忘了你实际上需要在Guice中注入一个会话级对象来强制Guice创建一个会话。愚蠢的我。
一旦我将一个会话范围的依赖注入到ShiroLoginResource并与之交互,那么一切都正常。
我会保持这个问题的开放性,因为它提供了一些有用的代码片段。