ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 BASIC 身份验证从网站注销用户?

如果他使用基本身份验证,是否可以从网站注销用户?

杀死会话是不够的,因为一旦用户通过身份验证,每个请求都包含登录信息,因此用户下次使用相同的凭据访问站点时会自动登录。

到目前为止唯一的解决方案是关闭浏览器,但从可用性的角度来看这是不可接受的。

只是好奇。你为什么要这样做?
能够以其他用户身份登录。
@DOK - 这是一个标准的社交黑客行为:用户应该能够在浏览器打开的情况下退出。假设您的一个用户在公共机器上访问该站点?他们需要明确注销,以便下一个用户无法像他们一样访问该站点。
@DOK还有一个问题是用户无法注销该站点。服务器可以清除授权cookie,甚至会话cookie。但是当浏览器加载 / 页面时,它们会自动重新登录。
我使用发送虚假请求注销的方法,但由于 AD 中存在 3 次登录失败的严格限制,因此将用户锁定在客户中。因此,建议谨慎使用此方法(发送虚假请求)。

B
Bergi

让用户单击指向 https://log:out@example.com/ 的链接。这将用无效的凭据覆盖现有凭据;将它们注销。


为什么这个没有得到更多的赞成票?对我来说,这似乎是一个简单而有效的解决方案。这种方法是否存在任何已知问题?
这在 Chrome 中将不再起作用,出于安全原因,Chrome 会忽略 URL 中的凭据。
这对我有用:) 我使用的是 Chrome 版本 32.0.1700.102
问题:使用 39.0 版 chrome,当我通过此方法单击注销链接时,Chrome 会记住错误的登录凭据,并在每次页面加载时提示输入新的登录凭据,直到我在没有任何指定登录凭据的情况下转到 example.com,清除 chrome 的内存。
嗨,我不能在 Chrome 上将它用于 https。
s
system PAUSE

bobince的答案的补充......

使用 Ajax,您可以将“注销”链接/按钮连接到 Javascript 函数。让此函数使用错误的用户名和密码发送 XMLHttpRequest。这应该会返回 401。然后将 document.location 设置回登录前页面。这样,用户在注销期间将永远不会看到额外的登录对话框,也不必记住输入错误的凭据。


好的 hack,让用户手动输入错误的凭据对于大多数 web 应用程序来说可能是不可接受的。
只需确保 XMLHttpRequest 未设置为异步,否则您可能会发现重定向将在注销请求完成之前发生。
您也可以使用相同的技巧进行登录。这样您就可以自定义登录对话框,而无需更改服务器的身份验证方法。这篇文章给出了一些好主意:http://www.peej.co.uk/articles/http-auth-with-html-forms.html
@davidjb 由于现在认为同步请求已弃用,因此另一种解决方案可能是在异步请求的回调中重定向用户。
David:chrome 现在允许 XHR 这样做,我可以确认它仍在 chrome canary 中工作。 bugs.chromium.org/p/chromium/issues/detail?id=435547
b
bobince

基本身份验证并非旨在管理注销。你可以做到,但不能完全自动。

您需要做的是让用户单击注销链接,并发送“401 Unauthorized”作为响应,使用与您发送请求登录的普通 401 相同的领域和相同的 URL 文件夹级别。

接下来必须指示他们输入错误的凭据,例如。一个空白的用户名和密码,作为响应,您会发回“您已成功注销”页面。然后,错误/空白凭据将覆盖以前的正确凭据。

简而言之,注销脚本反转了登录脚本的逻辑,仅在用户未传递正确凭据时才返回成功页面。

问题是有点好奇的“不要输入密码”密码框是否会满足用户的接受。尝试自动填充密码的密码管理器也可能在此处妨碍您。

编辑添加以响应评论:重新登录是一个稍微不同的问题(除非您显然需要两步注销/登录)。您必须拒绝(401)第一次访问重新登录链接的尝试,而不是接受第二次(可能具有不同的用户名/密码)。有几种方法可以做到这一点。一种方法是在注销链接中包含当前用户名(例如 /relogin?username),并在凭据与用户名匹配时拒绝。


我会尝试这种方法。注销(在这种情况下)的目的是使用户能够以不同的用户身份登录,因此这是完全可以接受的解决方案。至于自动填充密码,是否使用由用户决定。谢谢
这仍然是唯一的方法吗?我已经完成了一个可行的 ASP.Net MVC 和 jQuery 实现,但我仍然对它不满意:stackoverflow.com/questions/6277919
@Keith:仍然只有这个和systemPAUSE的答案(并非在所有浏览器上都有效,但在有效时比手动方法更流畅)。
W3C 在 HTML 规范上非常活跃。但是 HTTP 规范正在衰落。 W3C 应该在大约二十年前就解决了这个问题。随着 REST 服务使用的增加,需要一种强大的本机身份验证方法。
这在本地主机上的 Chrome 46 浏览中似乎无法正常工作。 Chrome 似乎保留了您指定的旧(正确)密码和新密码。导航到注销页面后,chrome 正确使用新密码,直到在您的站点上的页面上遇到未经授权的 401。在第一个 401 之后,Chrome 会恢复为旧的(正确的)密码。所以它似乎一开始并没有删除密码。
C
Carson

您可以完全在 JavaScript 中完成:

IE (长期以来)有用于清除基本身份验证缓存的标准 API:

document.execCommand("ClearAuthenticationCache")

工作时应该返回 true。在其他浏览器上返回 false、未定义或爆炸。

新浏览器(截至 2012 年 12 月:Chrome、FireFox、Safari)具有“神奇”行为。如果他们看到 成功 基本身份验证请求使用任何伪造的其他用户名(比如说 logout),他们会清除凭据缓存并可能将其设置为新的伪造用户名,您需要确保它是不是用于查看内容的有效用户名。

基本示例是:

var p = window.location.protocol + '//'
// current location must return 200 OK for this GET
window.location = window.location.href.replace(p, p + 'logout:password@')

执行上述操作的“异步”方式是使用 logout 用户名进行 AJAX 调用。例子:

(function(safeLocation){
    var outcome, u, m = "You should be logged out now.";
    // IE has a simple solution for it - API:
    try { outcome = document.execCommand("ClearAuthenticationCache") }catch(e){}
    // Other browsers need a larger solution - AJAX call with special user name - 'logout'.
    if (!outcome) {
        // Let's create an xmlhttp object
        outcome = (function(x){
            if (x) {
                // the reason we use "random" value for password is 
                // that browsers cache requests. changing
                // password effectively behaves like cache-busing.
                x.open("HEAD", safeLocation || location.href, true, "logout", (new Date()).getTime().toString())
                x.send("")
                // x.abort()
                return 1 // this is **speculative** "We are done." 
            } else {
                return
            }
        })(window.XMLHttpRequest ? new window.XMLHttpRequest() : ( window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : u ))
    }
    if (!outcome) {
        m = "Your browser is too old or too weird to support log out functionality. Close all windows and restart the browser."
    }
    alert(m)
    // return !!outcome
})(/*if present URI does not return 200 OK for GET, set some other 200 OK location here*/)

您也可以将其设为书签:

javascript:(function (c) {
  var a, b = "You should be logged out now.";
  try {
    a = document.execCommand("ClearAuthenticationCache")
  } catch (d) {
  }
  a || ((a = window.XMLHttpRequest ? new window.XMLHttpRequest : window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : void 0) ? (a.open("HEAD", c || location.href, !0, "logout", (new Date).getTime().toString()), a.send(""), a = 1) : a = void 0);
  a || (b = "Your browser is too old or too weird to support log out functionality. Close all windows and restart the browser.");
  alert(b)
})(/*pass safeLocation here if you need*/);

这是否需要对 logout 用户名和/或注销 URL 进行特殊的服务器端处理?
@ulidtko不,不应该-所有处理都是客户端的。唯一需要特殊处理的情况是名为 logout 的用户碰巧存在并且碰巧拥有生成的密码。在这种几乎不可能的情况下,将用户 ID 更改为系统中不存在的用户 ID。
我今天使用了上面的书签,效果很好。
我使用了它,它适用于 Chrome 和 FF。我只需要在我的 logout.php 页面上做一个额外的“GET”来清除 $_SESSION。
小书签也适用于 Edge。只需与 <a href='javascript:......need*/);'>Logout</a> 一起使用
m
mthoring

确认以下功能适用于 Firefox 40、Chrome 44、Opera 31 和 IE 11。
Bowser 用于浏览器检测,也使用 jQuery。

- secUrl 是密码的 url要从中注销的受保护区域。
- redirUrl 是非密码保护区域的 URL(注销成功页面)。
- 您可能希望增加重定向计时器(当前为 200 毫秒)。

功能注销(secUrl,redirUrl){如果(bowser.msie){document.execCommand('ClearAuthenticationCache','false'); } else if (bowser.gecko) { $.ajax({ async: false, url: secUrl, type: 'GET', username: 'logout' }); } else if (bowser.webkit) { var xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET", secUrl, true); xmlhttp.setRequestHeader("授权", "基本注销"); xmlhttp.send(); } else { alert("" + bowser.name + "不支持自动注销\n您必须关闭浏览器才能注销。"); } setTimeout(function () { window.location.href = redirUrl; }, 200); }


这是最全面的答案
$.ajax 变体是同步的 (async: false) 和 xmlhttp 变体是异步的(open() 中的 true)有什么原因吗?
Chrome 现在使用渲染引擎 Blink,因此您必须将 (bowser.gecko) 更改为 (bowser.gecko || bowser.blink)
为什么 gecko/blink 使用 $.ajax 而 webkit 使用 new XMLHttpRequest? gecko/blink 不应该能够做 XMLHttpRequest 而 webkit 也能做 $.ajax 吗?我很困惑。
R
Romuald Brunet

这是一个使用 jQuery 的非常简单的 Javascript 示例:

function logout(to_url) {
    var out = window.location.href.replace(/:\/\//, '://log:out@');

    jQuery.get(out).error(function() {
        window.location = to_url;
    });
}

此注销用户而没有再次向他显示浏览器登录框,然后将他重定向到已注销的页面


window.location= window.location.href.replace(/:\/\//, '://log:out@');
A
Alnitak

基本身份验证无法直接实现这一点。

HTTP 规范中没有让服务器告诉浏览器停止发送用户已经提供的凭据的机制。

有“黑客”(参见其他答案)通常涉及使用 XMLHttpRequest 发送带有不正确凭据的 HTTP 请求以覆盖最初提供的凭据。


理论上。从其他答案可以看出,实践证明并非如此。
正如您从其他答案中看到的那样,不是以可靠、一致和故障安全的方式!
C
Chiedo

其实很简单。

只需在浏览器中访问以下内容并使用错误的凭据:http://username:password@yourdomain.com

那应该“让你退出”。


但是用户必须是真正的用户,否则我得到“401 Unauthorized”,但使用 BACK 按钮我可以作为以前登录的用户继续工作。在深渊网络服务器 X1 (2.11.1) 上测试
重复的答案(参见上面的 Matthew Welborn)。
N
Nahuel Greco

只是为了记录,有一个名为 Clear-Site-Data 的新 HTTP 响应标头。如果您的服务器回复包含 Clear-Site-Data: "cookies" 标头,则应删除身份验证凭据(不仅是 cookie)。我在 Chrome 77 上对其进行了测试,但控制台上显示了此警告:

Clear-Site-Data header on 'https://localhost:9443/clear': Cleared data types:
"cookies". Clearing channel IDs and HTTP authentication cache is currently not
supported, as it breaks active network connections.

并且身份验证凭据没有被删除,因此(目前)这不适用于实现基本身份验证注销,但将来可能会。没有在其他浏览器上测试。

参考:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data

https://www.w3.org/TR/clear-site-data/

https://github.com/w3c/webappsec-clear-site-data

https://caniuse.com/#feat=mdn-http_headers_clear-site-data_cookies


developer.mozilla.org/en-US/docs/Web/HTTP/Headers/… - 看起来 Safari 不喜欢这个
C
Claudio

这适用于 IE/Netscape/Chrome :

      function ClearAuthentication(LogOffPage) 
  {
     var IsInternetExplorer = false;    

     try
     {
         var agt=navigator.userAgent.toLowerCase();
         if (agt.indexOf("msie") != -1) { IsInternetExplorer = true; }
     }
     catch(e)
     {
         IsInternetExplorer = false;    
     };

     if (IsInternetExplorer) 
     {
        // Logoff Internet Explorer
        document.execCommand("ClearAuthenticationCache");
        window.location = LogOffPage;
     }
     else 
     {
        // Logoff every other browsers
    $.ajax({
         username: 'unknown',
         password: 'WrongPassword',
             url: './cgi-bin/PrimoCgi',
         type: 'GET',
         beforeSend: function(xhr)
                 {
            xhr.setRequestHeader("Authorization", "Basic AAAAAAAAAAAAAAAAAAA=");
         },

                 error: function(err)
                 {
                    window.location = LogOffPage;
             }
    });
     }
  }


  $(document).ready(function () 
  {
      $('#Btn1').click(function () 
      {
         // Call Clear Authentication 
         ClearAuthentication("force_logout.html"); 
      });
  });          

E
Envek

您只需要在某个注销 URL 上重定向用户并在其上返回 401 Unauthorized 错误。在错误页面(必须无需基本身份验证即可访问)上,您需要提供指向主页的完整链接(包括方案和主机名)。用户将单击此链接,浏览器将再次要求提供凭据。

Nginx 的示例:

location /logout {
    return 401;
}

error_page 401 /errors/401.html;

location /errors {
    auth_basic off;
    ssi        on;
    ssi_types  text/html;
    alias /home/user/errors;
}

错误页面 /home/user/errors/401.html

<!DOCTYPE html>
<p>You're not authorised. <a href="<!--# echo var="scheme" -->://<!--# echo var="host" -->/">Login</a>.</p>

我会进一步建议在 401.html 中使用 http_host 而不是简单的 host,因为前者还会添加端口号(以防使用非标准端口)
T
Teo Bebekis

我刚刚在 Chrome (79)、Firefox (71) 和 Edge (44) 中测试了以下内容,它运行良好。它像上面提到的其他人一样应用脚本解决方案。

只需添加一个“注销”链接,点击后返回以下 html

    <div>You have been logged out. Redirecting to home...</div>    

<script>
    var XHR = new XMLHttpRequest();
    XHR.open("GET", "/Home/MyProtectedPage", true, "no user", "no password");
    XHR.send();

    setTimeout(function () {
        window.location.href = "/";
    }, 3000);
</script>

“单击时返回以下html”是什么意思?您的意思是将按钮的onclick功能设置为脚本中的javascript吗?
@Michael 不,只是一个锚元素,例如 Logout
这适用于 Chrome 97 和 Firefox 96 上的注销,但 Firefox 会记住“无用户”,并且在您尝试再次登录时不会提示再次登录。
A
Amir Mofakhar

将此添加到您的应用程序中:

@app.route('/logout')
def logout():
    return ('Logout', 401, {'WWW-Authenticate': 'Basic realm="Login required"'})

最好使用这个 return : return('Logout', 401)
C
Charlie
function logout() {
  var userAgent = navigator.userAgent.toLowerCase();

  if (userAgent.indexOf("msie") != -1) {
    document.execCommand("ClearAuthenticationCache", false);
  }

  xhr_objectCarte = null;

  if(window.XMLHttpRequest)
    xhr_object = new XMLHttpRequest();
  else if(window.ActiveXObject)
    xhr_object = new ActiveXObject("Microsoft.XMLHTTP");
  else
    alert ("Your browser doesn't support XMLHTTPREQUEST");

  xhr_object.open ('GET', 'http://yourserver.com/rep/index.php', false, 'username', 'password');
  xhr_object.send ("");
  xhr_object = null;

  document.location = 'http://yourserver.com'; 
  return false;
}

S
Sushovan Mukherjee
 function logout(url){
    var str = url.replace("http://", "http://" + new Date().getTime() + "@");
    var xmlhttp;
    if (window.XMLHttpRequest) xmlhttp=new XMLHttpRequest();
    else xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    xmlhttp.onreadystatechange=function()
    {
        if (xmlhttp.readyState==4) location.reload();
    }
    xmlhttp.open("GET",str,true);
    xmlhttp.setRequestHeader("Authorization","Basic xxxxxxxxxx")
    xmlhttp.send();
    return false;
}

F
Foad

根据我上面阅读的内容,我得到了一个适用于任何浏览器的简单解决方案:

1)在您的注销页面上,您将 ajax 调用到您的登录后端。您的登录后端必须接受注销用户。一旦后端接受,浏览器清除当前用户并假定“注销”用户。

$.ajax({
    async: false,
    url: 'http://your_login_backend',
    type: 'GET',
    username: 'logout'
});      

setTimeout(function () {
    window.location.href = 'http://normal_index';
}, 200);

2) 现在当用户回到正常的索引文件时,它将尝试使用用户“注销”自动进入系统,第二次你必须通过回复 401 来阻止它以调用登录/密码对话框。

3)有很多方法可以做到这一点,我创建了两个登录后端,一个接受注销用户,一个不接受。我的正常登录页面使用不接受的页面,我的注销页面使用接受的页面。


F
Fogus

除了 Mac 上的 Safari 之外,发送 https://invalid_login@hostname 在任何地方都可以正常工作(好吧,没有检查 Edge,但也应该在那里工作)。

当用户在 HTTP 基本身份验证弹出窗口中选择“记住密码”时,注销在 Safari 中不起作用。在这种情况下,密码存储在 Keychain Access 中(Finder > Applications > Utilities > Keychain Access(或 CMD+SPACE 并键入“Keychain Access”))。发送 https://invalid_login@hostname 不会影响钥匙串访问,因此使用此复选框无法在 Mac 上的 Safari 上注销。至少它对我来说是这样的。

MacOS Mojave (10.14.6)、Safari 12.1.2。

下面的代码在 Firefox (73)、Chrome (80) 和 Safari (12) 中运行良好。当用户导航到注销页面时,将执行代码并删除凭据。

    //It should return 401, necessary for Safari only
    const logoutUrl = 'https://example.com/logout'; 
    const xmlHttp = new XMLHttpRequest();
    xmlHttp.open('POST', logoutUrl, true, 'logout');
    xmlHttp.send();

同样出于某种原因,即使选择了“记住密码”,Safari 也不会在 HTTP 基本身份验证弹出窗口中保存凭据。其他浏览器正确执行此操作。


A
Amit Shah

此 JavaScript 必须适用于所有最新版本的浏览器:

//Detect Browser
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
    // Opera 8.0+ (UA detection to detect Blink/v8-powered Opera)
var isFirefox = typeof InstallTrigger !== 'undefined';   // Firefox 1.0+
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
    // At least Safari 3+: "[object HTMLElementConstructor]"
var isChrome = !!window.chrome && !isOpera;              // Chrome 1+
var isIE = /*@cc_on!@*/false || !!document.documentMode; // At least IE6
var Host = window.location.host;


//Clear Basic Realm Authentication
if(isIE){
//IE
    document.execCommand("ClearAuthenticationCache");
    window.location = '/';
}
else if(isSafari)
{//Safari. but this works mostly on all browser except chrome
    (function(safeLocation){
        var outcome, u, m = "You should be logged out now.";
        // IE has a simple solution for it - API:
        try { outcome = document.execCommand("ClearAuthenticationCache") }catch(e){}
        // Other browsers need a larger solution - AJAX call with special user name - 'logout'.
        if (!outcome) {
            // Let's create an xmlhttp object
            outcome = (function(x){
                if (x) {
                    // the reason we use "random" value for password is 
                    // that browsers cache requests. changing
                    // password effectively behaves like cache-busing.
                    x.open("HEAD", safeLocation || location.href, true, "logout", (new Date()).getTime().toString())
                    x.send("");
                    // x.abort()
                    return 1 // this is **speculative** "We are done." 
                } else {
                    return
                }
            })(window.XMLHttpRequest ? new window.XMLHttpRequest() : ( window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : u )) 
        }
        if (!outcome) {
            m = "Your browser is too old or too weird to support log out functionality. Close all windows and restart the browser."
        }
        alert(m);
        window.location = '/';
        // return !!outcome
    })(/*if present URI does not return 200 OK for GET, set some other 200 OK location here*/)
}
else{
//Firefox,Chrome
    window.location = 'http://log:out@'+Host+'/';
}

A
Ali

在地址栏中键入 chrome://restart,chrome 及其所有在后台运行的应用程序将重新启动并清除 Auth 密码缓存。


T
Tomalak

使用会话 ID (cookie)

使服务器上的会话 ID 无效

不接受会话 ID 无效的用户


当 cookie 不可用时,提供基本身份验证作为备用登录方案也很好。
M
Max

我为现代 Chrome 版本更新了 mthoring 的解决方案:

function logout(secUrl, redirUrl) {
    if (bowser.msie) {
        document.execCommand('ClearAuthenticationCache', 'false');
    } else if (bowser.gecko) {
        $.ajax({
            async: false,
            url: secUrl,
            type: 'GET',
            username: 'logout'
        });
    } else if (bowser.webkit || bowser.chrome) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open(\"GET\", secUrl, true);
        xmlhttp.setRequestHeader(\"Authorization\", \"Basic logout\");\
        xmlhttp.send();
    } else {
// http://stackoverflow.com/questions/5957822/how-to-clear-basic-authentication-details-in-chrome
        redirUrl = url.replace('http://', 'http://' + new Date().getTime() + '@');
    }
    setTimeout(function () {
        window.location.href = redirUrl;
    }, 200);
}

C
Carson

正如其他人所说,我们需要获取相同的 URL 并发送错误(例如,401:StatusUnauthorized 之类的),仅此而已。

我使用 Get 方法让它知道我需要注销,

这是使用 golang 编写的完整示例。

package main

import (
    "crypto/subtle"
    "fmt"
    "log"
    "net/http"
)

func BasicAuth(username, password, realm string, handlerFunc http.HandlerFunc) http.HandlerFunc {

    return func(w http.ResponseWriter, r *http.Request) {
        queryMap := r.URL.Query()
        if _, ok := queryMap["logout"]; ok { // localhost:8080/public/?logout
            w.WriteHeader(http.StatusUnauthorized) // 401
            _, _ = w.Write([]byte("Success logout!\n"))
            return
        }

        user, pass, ok := r.BasicAuth()

        if !ok ||
            subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 ||
            subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
            // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate
            w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`", charset="UTF-8"`)
            w.WriteHeader(http.StatusUnauthorized)
            _, _ = w.Write([]byte("Unauthorised.\n"))
            return
        }

        handlerFunc(w, r)
    }
}

type UserInfo struct {
    name string
    psw  string
}

func main() {

    portNumber := "8080"
    guest := UserInfo{"guest", "123"}

    // localhost:8080/public/  -> ./public/everyone
    publicHandler := http.StripPrefix(
        "/public/", http.FileServer(http.Dir("./public/everyone")),
    )

    publicHandlerFunc := func(w http.ResponseWriter, r *http.Request) {
        switch r.Method {
        case http.MethodGet:
            publicHandler.ServeHTTP(w, r)
        /*
            case http.MethodPost:
            case http.MethodPut:
            case http.MethodDelete:
        */
        default:
            return
        }
    }

    http.HandleFunc("/public/",
        BasicAuth(guest.name, guest.psw, "Please enter your username and password for this site",
            publicHandlerFunc),
    )

    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", portNumber), nil))
}

当您已经注销时,您需要刷新 (F5) 页面。否则,您可能会看到旧内容。


U
U. Windl

实际上,我认为基本身份验证旨在用于静态页面,而不是用于任何复杂的会话管理或 CGI 页面。

因此,当需要会话管理时,您应该设计一个经典的“登录表单”来查询用户和密码(也许也是第二个因素)。 CGI 表单处理程序应该将成功的身份验证转换为在服务器上和(在 cookie 中或作为 URI 的一部分)记住的会话 (ID)。

然后可以简单地通过使服务器(和客户端)“忘记”会话来实现注销。另一个优点是(即使是加密的)用户和密码不会随每个请求一起发送到服务器(而是会发送会话 ID)。

如果服务器上的会话 ID 与执行的“最后操作”的时间戳相结合,则可以通过将该时间戳与当前时间进行比较来实现会话超时:如果时间跨度太大,则通过忘记“超时”会话会话 ID。

对无效会话的任何请求都会导致重定向到登录页面(或者,如果您想让它更舒适,您也可以使用“重新验证表单”再次请求密码)。

作为概念证明,我实现了一个完全基于 URI 的完全无 cookie 的会话管理(会话 ID 始终是 URI 的一部分)。然而,完整的代码对于这个答案来说太长了。

当想要处理数千个并发会话时,必须特别注意性能。


A
A. Morel

对于使用 Windows 身份验证(也称为 Negotiate、Kerberos 或 NTLM 身份验证)的任何人,我将 ASP.NET Core 与 Angular 结合使用。

我找到了改变用户的有效方式!

我在javascript端修改了我的登录方法:

protected login(changeUser: boolean = false): Observable<AuthInfo> {
  let params = new HttpParams();
  if(changeUser) {
    let dateNow = this.datePipe.transform(new Date(), 'yyyy-MM-dd HH:mm:ss');
    params = params.set('changeUser', dateNow!);
  }
  const url: string = `${environment.yourAppsApiUrl}/Auth/login`;
  return this.http.get<AuthInfo>(url, { params: params });
}

这是我在后端的方法:

[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = NegotiateDefaults.AuthenticationScheme)]
public class AuthController : Controller
{
  [HttpGet("login")]
  public async Task<IActionResult> Login(DateTime? changeUser = null)
  {
      if (changeUser > DateTime.Now.AddSeconds(-3))
          return Unauthorized();

      ...
      ... (login process)
      ...

      return Ok(await _authService.GetToken());
    }
}

https://i.stack.imgur.com/A03Ht.png

如果我想更改用户,我现在将日期作为参数传输。

如果从那一刻起不超过 3 秒,我会返回 401 代码。

我完成了我的凭证,具有相同参数的相同请求被发送到后端。

由于已经过去了 3 秒多,我继续登录过程,但这次使用的是新凭据!


j
jwg

 
    function logout(secUrl, redirUrl) {
        if (bowser.msie) {
            document.execCommand('ClearAuthenticationCache', 'false');
        } else if (bowser.gecko) {
            $.ajax({
                async: false,
                url: secUrl,
                type: 'GET',
                username: 'logout'
            });
        } else if (bowser.webkit) {
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.open("GET", secUrl, true);
            xmlhttp.setRequestHeader("Authorization", "Basic logout");
            xmlhttp.send();
        } else {
            alert("Logging out automatically is unsupported for " + bowser.name
                + "\nYou must close the browser to log out.");
        }
        setTimeout(function () {
            window.location.href = redirUrl;
        }, 200);
    }

我尝试通过以下方式使用上述内容。

?php
    ob_start();
    session_start();
    require_once 'dbconnect.php';

    // if session is not set this will redirect to login page
    if( !isset($_SESSION['user']) ) {
        header("Location: index.php");
        exit;
    }
    // select loggedin users detail
    $res=mysql_query("SELECT * FROM users WHERE userId=".$_SESSION['user']);
    $userRow=mysql_fetch_array($res);
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Welcome - <?php echo $userRow['userEmail']; ?></title>
<link rel="stylesheet" href="assets/css/bootstrap.min.css" type="text/css"  />
<link rel="stylesheet" href="style.css" type="text/css" />

    <script src="assets/js/bowser.min.js"></script>
<script>
//function logout(secUrl, redirUrl)
//bowser = require('bowser');
function logout(secUrl, redirUrl) {
alert(redirUrl);
    if (bowser.msie) {
        document.execCommand('ClearAuthenticationCache', 'false');
    } else if (bowser.gecko) {
        $.ajax({
            async: false,
            url: secUrl,
            type: 'GET',
            username: 'logout'
        });
    } else if (bowser.webkit) {
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open("GET", secUrl, true);
        xmlhttp.setRequestHeader("Authorization", "Basic logout");
        xmlhttp.send();
    } else {
        alert("Logging out automatically is unsupported for " + bowser.name
            + "\nYou must close the browser to log out.");
    }
    window.location.assign(redirUrl);
    /*setTimeout(function () {
        window.location.href = redirUrl;
    }, 200);*/
}


function f1()
    {
       alert("f1 called");
       //form validation that recalls the page showing with supplied inputs.    
    }
</script>
</head>
<body>

    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="http://www.codingcage.com">Coding Cage</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="http://www.codingcage.com/2015/01/user-registration-and-login-script-using-php-mysql.html">Back to Article</a></li>
            <li><a href="http://www.codingcage.com/search/label/jQuery">jQuery</a></li>
            <li><a href="http://www.codingcage.com/search/label/PHP">PHP</a></li>
          </ul>
          <ul class="nav navbar-nav navbar-right">

            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
              <span class="glyphicon glyphicon-user"></span>&nbsp;Hi' <?php echo $userRow['userEmail']; ?>&nbsp;<span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="logout.php?logout"><span class="glyphicon glyphicon-log-out"></span>&nbsp;Sign Out</a></li>
              </ul>
            </li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav> 

    <div id="wrapper">

    <div class="container">

        <div class="page-header">
        <h3>Coding Cage - Programming Blog</h3>
        </div>

        <div class="row">
        <div class="col-lg-12" id="div_logout">
        <h1 onclick="logout(window.location.href, 'www.espncricinfo.com')">MichaelA1S1! Click here to see log out functionality upon click inside div</h1>
        </div>
        </div>

    </div>

    </div>

    <script src="assets/jquery-1.11.3-jquery.min.js"></script>
    <script src="assets/js/bootstrap.min.js"></script>


</body>
</html>
<?php ob_end_flush(); ?>

但它只会将您重定向到新位置。没有注销。