Reactjs 具有基于HttpOnly cookie的身份验证和会话管理的单页应用程序

Reactjs 具有基于HttpOnly cookie的身份验证和会话管理的单页应用程序,reactjs,cookies,vue.js,session-cookies,vuejs2,Reactjs,Cookies,Vue.js,Session Cookies,Vuejs2,几天来,我一直在为我的单页应用程序寻找一种安全的身份验证和会话管理机制。从大量关于SPA和身份验证的教程和博客文章来看,将JWT存储在localStorage或常规Cookie中似乎是最常见的方法,但这不是此应用程序的选项 要求 登录应该是可撤销的。例如,如果在用户的帐户上检测到可疑活动,则应该可以立即撤销该用户的访问权限并要求重新登录。类似地,密码重置之类的操作应该撤销所有现有登录 身份验证应该在Ajax上进行。之后不应进行浏览器重定向(“硬”重定向)。所有导航都应在水疗中心内进行 一切都应

几天来,我一直在为我的单页应用程序寻找一种安全的身份验证和会话管理机制。从大量关于SPA和身份验证的教程和博客文章来看,将JWT存储在localStorage或常规Cookie中似乎是最常见的方法,但这不是此应用程序的选项

要求

  • 登录应该是可撤销的。例如,如果在用户的帐户上检测到可疑活动,则应该可以立即撤销该用户的访问权限并要求重新登录。类似地,密码重置之类的操作应该撤销所有现有登录
  • 身份验证应该在Ajax上进行。之后不应进行浏览器重定向(“硬”重定向)。所有导航都应在水疗中心内进行
  • 一切都应该跨域工作。SPA将位于www.domain1.com,服务器将位于www.domain2.com
  • JavaScript应该无权访问服务器发送的敏感数据,例如会话ID。这是为了防止XSS攻击,恶意脚本可以从常规cookie、本地存储或会话存储中窃取令牌或会话ID
理想的机制似乎是基于cookie的身份验证,使用包含会话ID的
HttpOnly
cookie。流程的工作原理如下:

header("Access-Control-Allow-Origin: *");
  • 用户到达登录页面并提交其用户名和密码
  • 服务器对用户进行身份验证,并将会话ID作为
    HttpOnly
    响应cookie发送
  • SPA然后将此cookie包含在向服务器发出的后续XHR请求中。这似乎可以使用
    with credentials
    选项
  • 当向受保护的端点发出请求时,服务器将查找cookie。如果找到,它将对照数据库表交叉检查该会话ID,以确保该会话仍然有效
  • 当用户注销时,会话将从数据库中删除。下次用户到达站点时,SPA会收到401/403响应(因为会话已过期),然后将用户带到登录屏幕
  • 由于cookie具有
    HttpOnly
    标志,JavaScript将无法读取其内容,因此只要通过HTTPS传输,它就不会受到攻击

    挑战

    这是我遇到的具体问题。我的服务器配置为处理CORS请求。对用户进行身份验证后,它会在响应中正确发送cookie:

    HTTP/1.1 200 OK
    server: Cowboy
    date: Wed, 15 Mar 2017 22:35:46 GMT
    content-length: 59
    set-cookie: _myapp_key=SFMyNTYBbQAAABBn; path=/; HttpOnly
    content-type: application/json; charset=utf-8
    cache-control: max-age=0, private, must-revalidate
    x-request-id: qi2q2rtt7mpi9u9c703tp7idmfg4qs6o
    access-control-allow-origin: http://localhost:8080
    access-control-expose-headers: 
    access-control-allow-credentials: true
    vary: Origin
    
    但是,浏览器不保存cookie(当我检查Chrome的本地cookie时,它不在那里)。因此,当以下代码运行时:

    context.axios.post(LOGIN_URL, creds).then(response => {
      context.$router.push("/api/account")
    }
    
    此时将创建帐户页面:

    created() {
      this.axios.get(SERVER_URL + "/api/account/", {withCredentials: true}).then(response => {
        //do stuff
      }
    }
    
    此调用的标头中没有cookie。因此,服务器拒绝它

    GET /api/account/ HTTP/1.1
    Host: localhost:4000
    Connection: keep-alive
    Accept: application/json
    Origin: http://localhost:8080
    User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
    Referer: http://localhost:8080/
    Accept-Encoding: gzip, deflate, sdch, br
    Accept-Language: en-US,en;q=0.8,tr;q=0.6
    
    我是否需要做一些特殊的事情来确保浏览器在收到登录响应中的cookie后保存cookie?我读过的各种资料都说,浏览器只在用户被重定向时保存响应cookie,但我不想要任何“硬”重定向,因为这是SPA

    讨论中的SPA是用Vue.js编写的,但我想它适用于所有SPA。我想知道人们是如何处理这种情况的

    我在这个话题上读到的其他内容:


    使用凭据控件设置和发送cookie,因此在发布到登录时一定要将其打开,以便将返回的cookie保存在浏览器中。

    我在Vue.js 2上使用了此功能,凭据=true。从客户端站点设置凭据只完成了一半。您还需要从服务器设置响应头:

        header("Access-Control-Allow-Origin: http://localhost:8080");
        header("Access-Control-Allow-Credentials: true");
    
    您不能将通配符用于访问控制允许源代码,如下所示:

    header("Access-Control-Allow-Origin: *");
    
    指定credentials:true标头时,需要指定来源

    如您所见,这是一段PHP代码,您可以将其建模为NodeJS或您正在使用的任何服务器端脚本语言

    在VueJS中,我在main.js中设置credentials=true,如下所示:

    Vue.http.options.credentials = true
    
    在组件中,我使用ajax成功登录:

    <template>
    <div id="userprofile">
        <h2>User profile</h2>
        {{init()}}
    
    </div>
    </template>
    
    <script>
        export default {  
            name: 'UserProfile',
            methods: {
            init: function() {
    
    
                    // loggin in
                  console.log('Attempting to login');
    
                this.$http.get('https://localhost/api/login.php')
                .then(resource =>  {
                 // logging response - Notice I don't send any user or password for testing purposes  
    
                });
    
                // check the user profile
    
                    console.log('Getting user profile');
    
                    this.$http.get('https://localhost/api/userprofile.php')
                    .then(resource =>  {
                        console.log(resource.data);
                    })
    
            }
        }
        }
    
    </script>
    
    
    用户配置文件
    {{init()}}
    导出默认值{
    名称:“UserProfile”,
    方法:{
    init:function(){
    //登录
    log('尝试登录');
    这是。$http.get('https://localhost/api/login.php')
    。然后(资源=>{
    //日志响应-注意,我没有发送任何用于测试目的的用户或密码
    });
    //检查用户配置文件
    log(“获取用户配置文件”);
    这是。$http.get('https://localhost/api/userprofile.php')
    。然后(资源=>{
    console.log(resource.data);
    })
    }
    }
    }
    
    在服务器端,事情非常简单: Login.php on在不进行任何验证的情况下设置cookie(注意:此操作仅用于测试目的。不建议您在未经验证的情况下在生产中使用此代码)


    你好!您是否找到了此问题的原因?您是否找到了解决方案?如果用户已登录,如何在vue中检查客户端?使用JWT的所有其他解决方案只需检查它们是否可以在本地存储中找到令牌,如果可以,则得出用户必须登录的结论。
    <?php
    
      header("Access-Control-Allow-Origin: http://localhost:8080");
        header("Access-Control-Allow-Credentials: true");
    
    
    if(isset($_COOKIE['user'])){
      echo "Congratulations the user is ". $_COOKIE['user'];
    
    }else{
      echo "Not allowed to access";
    }