为什么 Shiro 的 AnonymousFilter 不在这个例子中创建新的网络会话?

Why doesn't Shiro's AnonymousFilter create new web sessions in this example?

我有两个使用 Shiro 保护的应用程序,允许匿名访问所有页面。一个是部署在 Jetty 服务器内的 WAR,另一个是带有嵌入式 Jetty 服务器的独立 Java 应用程序。

  1. 为什么独立应用程序不创建 session,而 WAR 应用程序创建?
  2. 如何配置独立应用程序以便创建 sessions?
  3. 为什么独立应用程序需要在 shiro.ini 中明确定义 session 管理器,而 WAR 应用程序不需要? (删除它意味着 authcBasic 过滤器也不起作用)。

WAR 应用

WEB-INF/shiro.ini:

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager

[urls]
/** = anon

WEB-INF/web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1">

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<welcome-file-list>
    <welcome-file>home.jsp</welcome-file>
</welcome-file-list>

</web-app>

home.jsp:

<!DOCTYPE html>
<html>
<body>
</body>
</html>

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress osmorcNonOsgiMavenDependency -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.foo.example</groupId>
    <artifactId>apache-shiro-tutorial-webapp</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>Apache Shiro Tutorial Webapp</name>
    <packaging>war</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.1.0.v20131115</version>
                <configuration>
                    <webApp>
                        <contextPath>/</contextPath>
                    </webApp>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.2.2</version>
        </dependency>
    </dependencies>
</project>

独立应用程序

类路径:shiro.ini:

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager

[urls]
/** = anon

Main.java:

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.env.EnvironmentLoaderListener;
import org.apache.shiro.web.servlet.ShiroFilter;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import static java.util.EnumSet.allOf;

public class Main {

    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        ShiroFilter shiroFilter = new ShiroFilter();

        ServletContextHandler context = new ServletContextHandler();
        context.addEventListener(new EnvironmentLoaderListener());
        context.setContextPath("/");
        context.addFilter(new FilterHolder(shiroFilter), "/", allOf(DispatcherType.class));
        context.addServlet(new ServletHolder(dummyServlet), "/");

        server.setHandler(context);

        server.start();
        SecurityUtils.setSecurityManager(shiroFilter.getSecurityManager());
        server.join();
    }

    private static HttpServlet dummyServlet = new HttpServlet() {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().write("OK");
        }
    };
}

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>test</groupId>
    <artifactId>test</artifactId>
    <version>1.0-SNAPSHOT</version>

<dependencies>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-server</artifactId>
        <version>9.3.1.v20150714</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlet</artifactId>
        <version>9.3.1.v20150714</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-web</artifactId>
        <version>1.2.2</version>
    </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.5</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.13</version>
            <scope>runtime</scope>
        </dependency>
</dependencies>

</project>

证明独立应用程序有效(因此 AnonymousFilter 是问题所在)

在独立应用程序中,如果我将 shiro.ini 文件替换为:

[main]
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager

[users]
name = password

[urls]
/** = authcBasic

然后我可以以 "name" 身份登录并创建 session 。它似乎只是拒绝创建 sessions.

的匿名过滤器

其他信息

当我说 "a session is created" 时,我的意思是当我浏览到 localhost:8080/ 时,我可以在服务器的响应中看到 Set-Cookie: JSESSIONID=blahblahblah header。独立应用程序中的匿名过滤器从未设置过此类 cookie。

在 Web 应用程序中,Shiro 默认将会话创建委托给容器:

来自http://shiro.apache.org/web.html#Web-SessionManagement

In web environments, Shiro's default session manager SessionManager implementation is the ServletContainerSessionManager. This very simple implementation delegates all session management duties (including session clustering if the servlet container supports it) to the runtime Servlet container. It is essentially a bridge for Shiro's session API to the servlet container and does little else.

当您 运行 独立应用程序时,您可以通过调用 SecurityUtils.getSubject().getSession(); (docu-link) 来获取会话。 BasicAuth 的实现可能是隐式的, 使用 anon 时尝试在代码中使用 getSession()

我将此问题的原因追查到过滤器的 url 模式:

/*

/