是否可以指示网络会话对单个站点(或页面)有效?

Is it possible to indicate that the web session will be valid for a single site (or page)?

让我好好解释一下。我正在将我的应用程序与 Jasper Report Server 集成,并阻止通过 URL(使用 GET)发送用户名和密码以查看报告。

为此,我使用 rest_v2 service 通过 POST 请求对用户进行身份验证,并使用带有 JSESSION 的响应主体将请求重定向到 Jasper Report(这次是网站不会重定向到登录站点,因为我获得了有效的会话令牌)。

我想做的是限制该会话可用的站点,我只希望它对报告页面有效,并且如果用户尝试访问存储库,则该会话将不会可用并且网页重定向到 jasper 登录屏幕

示例:用户请求可以在 url

中访问的报告

/jasperserver/flow.html?_flowId=viewReportFlow&_flowId=viewReportFlow&ParentFolderUri=%2FReports&reportUnit=%2FTest%2FJasper_Report

如果用户尝试在此 URL 之外访问此处,则会话将不再有效。

这是我的来源

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {      
    HttpPost post = new HttpPost("http://localhost:8080/jasperserver/rest_v2/login");
    
    int coderes;
    String username = request.getParameter("username");
    String pass = request.getParameter("pass");
    
    List<NameValuePair> urlParameters = new ArrayList<>();
    urlParameters.add(new BasicNameValuePair("j_username",username));
    urlParameters.add(new BasicNameValuePair("j_password",pass));
    
    post.setHeader("type", "POST");
    post.setHeader("cors", "true");
    post.setHeader("contentType", "application/x-www-form-urlencoded");
    post.setHeader("secure","true");
    
    post.setEntity(new UrlEncodedFormEntity(urlParameters));    
    
    Header[] headers = null;
    
    try(CloseableHttpClient client = HttpClients.createDefault();
            CloseableHttpResponse chres = client.execute(post)){    
        StatusLine status = chres.getStatusLine();
        coderes = status.getStatusCode();
        headers = chres.getAllHeaders();
    }
    
    if(coderes == 200) {
        for(int i = 0; i < headers.length; i++) {
            if(headers[i].getName().equals("Set-Cookie")) {
                response.addHeader(headers[i].getName(), ServletUtils.setCookieValue(headers[i].getValue().split(";"), "/jasperserver/flow.html?_flowId=viewReportFlow&_flowId=viewReportFlow&ParentFolderUri=%2FPublished&reportUnit=%2FPublished%2FUser_Report&standAlone=true"));
            } else {
                response.addHeader(headers[i].getName(), headers[i].getValue());
            }
        }
        response.sendRedirect("http://localhost:8080/jasperserver/flow.html?_flowId=viewReportFlow&_flowId=viewReportFlow&ParentFolderUri=%2FPublished&reportUnit=%2FPublished%2FUser_Report&standAlone=true");
    } else {
        response.getWriter().println("Incorrect Credentials");
    }
}

setCookieValue 方法

public static String setCookieValue(String[] attr, String requestUrl) {
    Date targetTime = Calendar.getInstance().getTime();
    
    SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
    
    targetTime = DateUtils.addMinutes(targetTime, 5);
            
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < attr.length; i++){
          if(attr[i].contains("userLocale")){
              attr[i] = "userLocale=es_ES";
          }else if(attr[i].contains("Expires")) {
              attr[i] = "Expires=" + fmt.format(targetTime) + " GMT";
          }else if(attr[i].contains("Path")){
              attr[i] = requestUrl;
          }
          sb.append(attr[i]).append(";");
    }
    return sb.toString();
}

在这个方法中,我尝试做的是将请求的 URL 放在属性 Path 中,因为我从这个 site 中了解到:

This method gets the path to which this cookie applies.

也许我输入的 URL 有误,或者我使用了错误的属性。

我觉得有可能

我的想法太难实现了,所以我决定创建一个具有“仅执行”权限的新角色来重新创建这个“效果”。

如果用户尝试浏览报告存储库,则不会加载文件夹。

理论上您可以操纵 Java HTTP 会话的 cookie(它至少适用于 Tomcat 和 Spring 启动)。设置会话 cookie Tomcat 可以通过 HttpServletResponse 实例访问它。您可以覆盖 JSESSION cookie 替换 Path 属性。

但是 JEE 标准并未涵盖这种手动操作,调试此解决方案将非常痛苦。

我有个更好的主意! Jasper Report Server 是否作为第三方 servlet 嵌入到您的应用程序中?如果是,我建议围绕这个 Servlet 包装一个自定义过滤器。过滤器可以在“web.xml”中指定。在过滤器内部,您需要为 HttpServletRequest 创建一个代理并注入您想要的任何身份验证信息。您可以在此级别上模拟任何内容,包括虚假的 HTTP 会话。