使用Shiro登录后,主题不再在会话中进行身份验证

时间:2015-06-02 05:17:26

标签: java jersey guice shiro

我正在使用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。

1 个答案:

答案 0 :(得分:0)

好的,这最终不是Shiro的问题。我正在使用从ShiroLoginResource到ShiroResource的两个不同的会话。

我忘了你实际上需要在Guice中注入一个会话级对象来强制Guice创建一个会话。愚蠢的我。

一旦我将一个会话范围的依赖注入到ShiroLoginResource并与之交互,那么一切都正常。

我会保持这个问题的开放性,因为它提供了一些有用的代码片段。