GDPR、Cookies 同意横幅 Flutter web

2023-11-26

我正在使用 Flutter 构建我的网站,但网络编程对我来说非常陌生,我不太确定我到底理解 Cookie 是如何工作的。 我仍然需要了解哪些 cookie 将写入何处,以及我从哪里获取这些 cookie。 构建横幅来管理应该很容易,如果我没记错的话,它应该是主页中弹出的第一件事。 例如,中横幅只是一个可关闭的横幅,摆动消息To make Medium work, we log user data. By using Medium, you agree to our Privacy Policy.带有隐私政策链接,但没有任何选择加入,因此看起来不符合 GDPR。

Here https://medium.com/@mayur_solanki/flutter-web-forming-hummingbird-ba52f5135fb0展示了 flutter web 中 cookies 是如何写入和读取的

html.window.localStorage['key']
html.window.sessionStorage['key']
html.window.document.cookie

html.window.localStorage['local_value'] = localStorage;
html.window.sessionStorage['session_value'] = sessionStorage;
html.window.document.cookie= "username=${cookies}; expires=Thu, 18 Dec 2020 12:00:00 UTC";

据我了解,cookies 就是这些类型。

第一方: 为了跟踪用户行为(页面访问、用户数量等),当我使用谷歌分析时,我确实需要征求这些行为的同意。 这里Google Analytics、Flutter、cookie 和通用数据保护条例 (GDPR)显示了如何激活/停用它,所以如果我没有错的话,我不应该自己存储任何东西。

第三者: 例如,这些内容可能来自我主页上的 YouTube 链接视频,因此我也需要征求这些内容的同意。 还没有检查过,但我想它应该类似于 Google Analytics

会话cookie: 这些应该用来记住购物篮中的物品。 我不应该需要这些..

持久cookie: 这些应该是为了保持用户的登录状态。 其中一个网页是Retailer access,这是零售商的应用程序(市场的供应方)。 我正在使用 Google 签名来登录用户,所以我应该需要这些,因为在导航到时它总是向用户呈现登录表单Retailer access即使他们登录后。

安全cookie: 这些仅适用于 https,用于结帐/付款页面。 在我的网站中,零售商的应用程序仅创建产品、管理研讨会预订以及处理与客户的沟通。 移动应用程序(市场的需求方)是使用 Stripe 进行所有付款的地方,因此我不必在网络上存储任何内容......对吗?

抱歉问了这么长的问题,我希望它足够清楚。 感谢您的帮助。


我基本上遇到了这个问题,因为我还使用第三方脚本(firebase、stripe...),并且在运行任何这些脚本之前我需要用户的同意。

我围绕 Yett 构建我的解决方案(https://github.com/elbywan/yett),它会阻止属于先前定义的黑名单的脚本。你甚至可以自己实现这个功能,作者写了一个有趣的中等文章.

就我而言,我只有“基本”脚本,因此我构建了一个解决方案,其中仅当用户同意所有必要的脚本时,flutter 应用程序才会加载。但如果需要对用户的 cookie 设置进行更细粒度的控制,调整此解决方案应该不会太困难,并且我添加了第二个“分析”条目作为可能的起点。

我将用户的设置存储在 localStorage 中,并直接在应用程序启动时检索它们以创建黑名单并决定是否应显示 cookie 横幅。

这是我的index.html.

它引用了以下脚本:get_consent.js, set_consent.js, init_firebase.js and load_app.js(有关它们的更多信息如下)。

<!DOCTYPE html>
<html>
<head>
  <!--
    If you are serving your web app in a path other than the root, change the
    href value below to reflect the base path you are serving from.

    The path provided below has to start and end with a slash "/" in order for
    it to work correctly.

    For more details:
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
  -->
  <base href="/">

  <meta charset="UTF-8">
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
  <meta name="description" content="A new Flutter project.">

  <!-- iOS meta tags & icons -->
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="apple-mobile-web-app-title" content="flutter_utils">
  <link rel="apple-touch-icon" href="icons/Icon-192.png">
  <!-- Assigns blacklist of urls based on localStorage (must be placed before yett script) -->
  <script src="get_consent.js"></script>
  <!-- Yett is used to block all third-party scripts that are part of the blacklist (must be placed before all other (third-party) scripts) -->
  <script src="https://unpkg.com/yett"></script>
  <script src="https://js.stripe.com/v3/"></script>

  <title>flutter_utils</title>
  <link rel="manifest" href="manifest.json">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <!-- The standard consent popup (hidden by default) -->
  <div id="consent-popup" class="hidden consent-div">
    <h2>We use cookies and other technologies</h2>
    <p>This website uses cookies and similar functions to process end device information and personal data. The processing serves the integration of content, external services and elements of third parties, statistical analysis/measurement, personalized advertising and the integration of social media. Depending on the function, data may be passed on to third parties within the EU in the process. Your consent is always voluntary, not required for the use of our website and can be rejected or revoked at any time via the icon at the bottom right.
    </p>
    <div>
      <button id="accept-btn" class="btn inline">Accept</button>
      <button id="reject-btn" class="btn inline">Reject</button>
      <button id="info-btn" class="btn inline">More info</button>    
    </div>
  </div>
  <!-- Detailed consent popup allows the user to control scripts by their category -->
  <div id="consent-popup-details" class="hidden consent-div">
    <h2>Choose what to accept</h2>
    <div>
      <div class="row-div">
        <h3>Essential</h3>
        <label class="switch">
          <!-- Essentials must always be checked -->
          <input id="essential-cb" type="checkbox" checked disabled=true>
          <span class="slider round"></span>
        </label>    
      </div>
      <p>
      Here you can find all technically necessary scripts, cookies and other elements that are necessary for the operation of the website.
      </p>
    </div>
        <div>
      <div class="row-div">
        <h3>Analytics</h3>
        <label class="switch">
          <input id ="analytics-cb" type="checkbox">
          <span class="slider round"></span>
        </label>    
      </div>
      <p>
      For the site, visitors, web page views and diveerse other data are stored anonymously.
      </p>
    </div>
    <div>
      <button id="save-btn" class="btn inline">Save</button>
      <button id="cancel-btn" class="btn inline">Cancel</button>   
    </div>
  </div>
  <!-- Updates localStorage with user's cookie settings -->
  <script src="set_consent.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-firestore.js"></script>
  <script src="https://www.gstatic.com/firebasejs/8.6.1/firebase-storage.js"></script>
  <!-- Initializes firebase (if user gave consent) -->
  <script src="init_firebase.js"></script>
  <!-- Loads flutter app (if user gave consent) -->
  <script src="load_app.js"></script>     
</body>
</html>

The get_consent.js是第一个脚本,从 localStorage 检索用户的设置并定义 Yett 黑名单:

const essentialCookies = ["js.stripe.com", "www.gstatic.com"];
const analyticsCookies = ["www.google-analytics.com"];
const allCookies = [...essentialCookies, ...analyticsCookies];
const consentPropertyName = "cookie_consent";

const retrieveConsentSettings = () => {
  const consentJsonString = localStorage.getItem(consentPropertyName);
  return JSON.parse(consentJsonString);
};

const checkConsentIsMissing = () => {
  const consentObj = retrieveConsentSettings();
  if (!consentObj || consentObj.length == 0) {
    return true;
  }
  return false;
};

const consentIsMissing = checkConsentIsMissing();

var blacklist;
if (consentIsMissing) {
  blacklist = allCookies;
} else {
  const acceptedCookies = retrieveConsentSettings();
  // Remove all script urls from blacklist that the user accepts (if all are accepted the blacklist will be empty)
  blacklist = allCookies.filter( ( el ) => !acceptedCookies.includes( el ) );
}

// Yett blacklist expects list of RegExp objects
var blacklistRegEx = [];
for (let index = 0; index < blacklist.length; index++) {
  const regExp = new RegExp(blacklist[index]);
  blacklistRegEx.push(regExp);
}

YETT_BLACKLIST = blacklistRegEx;

set_consent.js负责使用用户的设置更新 localStorage 并隐藏/显示相应的 div 以获取 cookie 同意。通常,人们可以简单地调用window.yett.unblock()解除阻止脚本,但由于它们的顺序很重要,我决定在更新 localStorage 后简单地重新加载窗口:

const saveToStorage = (acceptedCookies) => {
  const jsonString = JSON.stringify(acceptedCookies);
  localStorage.setItem(consentPropertyName, jsonString);
};

window.onload = () => {
  const consentPopup = document.getElementById("consent-popup");
  const consentPopupDetails = document.getElementById("consent-popup-details");
  const acceptBtn = document.getElementById("accept-btn");
  const moreInfoBtn = document.getElementById("info-btn");
  const saveBtn = document.getElementById("save-btn");
  const cancelBtn = document.getElementById("cancel-btn");
  const rejectBtn = document.getElementById("reject-btn");

  const acceptFn = (event) => {
    const cookiesTmp = [...essentialCookies, ...analyticsCookies];
    saveToStorage(cookiesTmp);
    // Reload window after localStorage was updated.
    // The blacklist will then only contain items the user has not yet consented to.
    window.location.reload();
  };

  const cancelFn = (event) => {
    consentPopup.classList.remove("hidden");
    consentPopupDetails.classList.add("hidden");
  };

  const rejectFn = (event) => {
    console.log("Rejected!");
    // Possible To-Do: Show placeholder content if even essential scripts are rejected.
  };

  const showDetailsFn = () => {
    consentPopup.classList.add("hidden");
    consentPopupDetails.classList.remove("hidden");
  };

  const saveFn = (event) => {
    const analyticsChecked = document.getElementById("analytics-cb").checked;
    var cookiesTmp = [...essentialCookies];
    if (analyticsChecked) {
      cookiesTmp.push(...analyticsCookies);
    }
    saveToStorage(cookiesTmp);
    // Reload window after localStorage was updated.
    // The blacklist will then only contain items the user has not yet consented to.
    window.location.reload();
  };

  acceptBtn.addEventListener("click", acceptFn);
  moreInfoBtn.addEventListener("click", showDetailsFn);
  saveBtn.addEventListener("click", saveFn);
  cancelBtn.addEventListener("click", cancelFn);
  rejectBtn.addEventListener("click", rejectFn);

  if (consentIsMissing) {
    consentPopup.classList.remove("hidden");
  }
};

init_firebase.js是用于初始化服务的常用脚本,但我仅在获得同意的情况下进行初始化:

var firebaseConfig = {
  // your standard config
};

// Initialize Firebase only if user consented
if (!consentIsMissing) {
  firebase.initializeApp(firebaseConfig);
}

相同的逻辑应用于脚本load_app.js。仅当用户同意时才会加载 Flutter 应用程序。

因此,人们可能会在其中添加一些后备内容index.html如果用户拒绝必要的脚本,则会显示该信息。根据您的使用案例,也可能是无论如何加载应用程序的选项,然后通过从 localStorage 访问用户的设置来在应用程序内进行区分。

var serviceWorkerVersion = null;
var scriptLoaded = false;
function loadMainDartJs() {
  if (scriptLoaded) {
    return;
  }
  scriptLoaded = true;
  var scriptTag = document.createElement("script");
  scriptTag.src = "main.dart.js";
  scriptTag.type = "application/javascript";
  document.body.append(scriptTag);
}

// Load app only if user consented
if (!consentIsMissing) {
  if ("serviceWorker" in navigator) {
    // Service workers are supported. Use them.
    window.addEventListener("load", function () {
      // Wait for registration to finish before dropping the <script> tag.
      // Otherwise, the browser will load the script multiple times,
      // potentially different versions.
      var serviceWorkerUrl =
        "flutter_service_worker.js?v=" + serviceWorkerVersion;
      navigator.serviceWorker.register(serviceWorkerUrl).then((reg) => {
        function waitForActivation(serviceWorker) {
          serviceWorker.addEventListener("statechange", () => {
            if (serviceWorker.state == "activated") {
              console.log("Installed new service worker.");
              loadMainDartJs();
            }
          });
        }
        if (!reg.active && (reg.installing || reg.waiting)) {
          // No active web worker and we have installed or are installing
          // one for the first time. Simply wait for it to activate.
          waitForActivation(reg.installing ?? reg.waiting);
        } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
          // When the app updates the serviceWorkerVersion changes, so we
          // need to ask the service worker to update.
          console.log("New service worker available.");
          reg.update();
          waitForActivation(reg.installing);
        } else {
          // Existing service worker is still good.
          console.log("Loading app from service worker.");
          loadMainDartJs();
        }
      });

      // If service worker doesn't succeed in a reasonable amount of time,
      // fallback to plaint <script> tag.
      setTimeout(() => {
        if (!scriptLoaded) {
          console.warn(
            "Failed to load app from service worker. Falling back to plain <script> tag."
          );
          loadMainDartJs();
        }
      }, 4000);
    });
  } else {
    // Service workers not supported. Just drop the <script> tag.
    loadMainDartJs();
  }
}

这是我的style.css:

html,
body {
  height: 100%;
  width: 100%;
  background-color: #2d2d2d;
  font-family: Arial, Helvetica, sans-serif;
}

.hidden {
  display: none;
  visibility: hidden;
}

.consent-div {
  position: fixed;
  bottom: 40px;
  left: 10%;
  right: 10%;
  width: 80%;
  padding: 14px 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  background-color: #eee;
  border-radius: 5px;
  box-shadow: 0 0 5px 5px rgba(0, 0, 0, 0.2);
}

.row-div {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

#accept-btn,
#save-btn {
  background-color: #103900;
}

#reject-btn,
#cancel-btn {
  background-color: #ff0000;
}

.btn {
  height: 25px;
  width: 140px;
  background-color: #777;
  border: none;
  color: white;
  border-radius: 5px;
  cursor: pointer;
}

.inline {
  display: inline-block;
  margin-right: 5px;
}

h2 {
  margin-block-start: 0.5em;
  margin-block-end: 0em;
}

h3 {
  margin-block-start: 0.5em;
  margin-block-end: 0em;
}

/* The switch - the box around the slider */
.switch {
  position: relative;
  display: inline-block;
  width: 50px;
  height: 25px;
}

/* Hide default HTML checkbox */
.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

/* The slider */
.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc;
}

.slider:before {
  position: absolute;
  content: "";
  height: 18px;
  width: 18px;
  left: 4px;
  bottom: 4px;
  background-color: white;
}

input:checked + .slider {
  background-color: #2196f3;
}

input:focus + .slider {
  box-shadow: 0 0 1px #2196f3;
}

input:checked + .slider:before {
  -webkit-transform: translateX(24px);
  -ms-transform: translateX(24px);
  transform: translateX(24px);
}

/* Rounded sliders */
.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GDPR、Cookies 同意横幅 Flutter web 的相关文章

  • Cookie 仍通过 ini_set('session.cookie_secure',1); 在 HTTP 上设置

    我的配置文件如下所示 ini set session cookie secure 1 ini set session cookie httponly 1 ini set session use only cookies 1 session
  • ExpressJS 设置/获取/使用 cookie

    无法获取请求中设置的 cookie 我设置我的cookie response cookie name My name 我想以这种方式获取我的cookie 它以前工作过 但我更改了快速配置 我不知道现在似乎是什么问题 request cook
  • setcookie() 和 session_set_cookie_params() 函数之间的区别

    我试图理解 PHP 函数 setcookie 和 session set cookie params 之间的区别 看起来两个函数都在执行相同类型的任务 但 setcookie 可用于创建具有名称和值的 cookie 我试图理解 PHP 手册
  • Symfony 3 跨子域共享 cookie?

    我想跨任何子域共享 cookie 这应该可以让我保留会话 我使用的是 Symfony 框架 3 0 版 我读到您应该设置以下内容 app config config yml session cookie domain localhost 我
  • Cookie 未设置或首次不起作用

    在每个页面上 我都设置了一个 cookie 来为与该会话对应的标题按钮着色 问题是 当我第一次在不同的部分打开页面时 cookie 仍然是旧的 彩色按钮也是如此 然后 如果我再次单击同一按钮 则 cookie 会被正确设置 为什么 这是我的
  • 如何在Android webview中永久保存cookie?

    通过下面的代码 我已经能够保存 cookie 但是一旦我关闭应用程序 cookie 就会消失 这是如何引起的以及如何解决 package com jkjljkj import android app Activity import andr
  • ASP.NET MVC 4 cookie 消失

    我有一个 ASP NET 应用程序 它将身份验证 cookie 发送到 ASP NET MVC 应用程序 用作后台应用程序 我添加了一个全局过滤器 用于检查身份验证 cookie 的每个控制器操作 如果cookie存在 则允许用户进入该页面
  • 在第三方网站的 iframe 中访问时,未为子域设置 Django csrf cookie

    到目前为止 我的应用程序运行良好 所有操作都是通过访问其公共 IP 来完成的 现在 它被添加到主站点 名称为 app mainsite com 这样就可以访问了 我可以登录等等一切 但我的应用程序有点特别 它的某个功能允许用户在任何第三方网
  • Flutter TextButton splashColor 属性

    我正在使用FlatButton并传递了属性 FlatButton splashColor Colors transparent highlightColor Colors transparent child The 文档称 FlatButt
  • res.cookie未在浏览器中设置cookie

    我目前正在尝试使用 React 客户端设置 Node Express 应用程序以与之交互 我设置了护照来处理 JWT 身份验证 当用户登录时 我验证电子邮件 密码 然后我设置cookie res cookie jwt token httpO
  • 如何使用 Java 以编程方式登录 Facebook?

    我正在尝试编写一个可以自动登录 Facebook 的 Java 程序 到目前为止 我已经得到了以下代码 可以将主页 html 页面下载到字符串中 但不知道如何发送电子邮件和密码来登录 Facebook Java 程序还需要处理返回的 coo
  • 错误:$.cookie 不是函数

    我使用以下代码添加了 jQuery 插件 我的激活cookie的代码如下 document ready function ul sub menu a click function sliderid prodcls css display n
  • Angular 2/4 存储令牌的位置

    我有一个用于生成令牌的 REST API 我在 Angular 4 客户端中使用它 但问题是在哪里存储该令牌 在互联网上我发现我可以存储在本地存储或cookie中 所以我的问题是 如果存储令牌是本地存储 并且我刚刚从另一个浏览器复制了有效令
  • iframe 不读取 Chrome 中的 cookie

    Chrome 不允许子 iframe 读取自己的 cookie 我有一个带有子 iframe 的父网页 家长在https first site com 孩子在 父级内部 cookie set with 小路 安全 真实 仅http 假 域名
  • 如何:默认显示 video_player 插件的播放控件 (flutter-web)

    有什么方法可以默认显示视频播放器的控件吗 如果我在浏览器中右键单击视频 我就可以显示它们 所以我假设必须有一种默认显示的方法 我无法找到默认显示 video player 控件的方法 但使用了这个包 它在 Flutter web 上工作得很
  • 如何从 Flutter Web 中的 URL 中删除哈希 (#)

    Flutter Web 项目的默认 URL 定义了包含主题标签的 URL 如下 http localhost 41521 peaple 我想删除这个 如下所示 http localhost 41521 peaple 我怎么解决这个问题 您现
  • 使用 chrome 扩展和 Django 进行身份验证

    对于那些熟悉 django 和 chrome 扩展的人 如何使用 cookie 进行身份验证 以便当您登录 django 制作的网站时 您的 chrome 扩展程序也会登录并激活 谢谢 您的 Chrome 扩展程序 通过 Javascrip
  • 如何在 C# 中将 cookie 过期设置为“会话”?

    不言自明 在 PHP 中 解决方案是将 cookie 过期设置为 0 我不确定 C 因为它需要 DateTime 值 的文档Cookie 过期 http msdn microsoft com en us library system net
  • $_COOKIE[] 设置后似乎没有反映更改

    我不记得过去使用 Cookie 时遇到过很多问题 但我在尝试时遇到了一些意想不到的结果 我在本地主机上运行 因此我的域设置 这将产生以下输出 Cookie Set Cookie equals 457718770 shou
  • CookieManager.getInstance().removeAllCookie();不删除所有cookie

    我在应用程序的 onCreate 中调用 CookieManager getInstance removeAllCookie 我遇到了一个奇怪的问题 我看到 GET 请求中传递了意外的 cookie 值 事实上 cookie 值是一个非常非

随机推荐