Programing

BASIC 인증을 사용하여 웹 사이트에서 사용자를 로그 아웃하는 방법은 무엇입니까?

lottogame 2020. 4. 2. 08:11
반응형

BASIC 인증을 사용하여 웹 사이트에서 사용자를 로그 아웃하는 방법은 무엇입니까?


기본 인증을 사용하는 경우 웹 사이트에서 사용자를 로그 아웃 할 수 있습니까?

사용자가 인증되면 각 요청에 로그인 정보가 포함되므로 다음 번에 동일한 자격 증명을 사용하여 사이트에 액세스 할 때 사용자가 자동으로 로그인되므로 킬 세션이 충분하지 않습니다.

지금까지 유일한 해결책은 브라우저를 닫는 것이지만 사용성 측면에서는 받아 들일 수 없습니다.


기본 인증은 로그 아웃을 관리하도록 설계되지 않았습니다. 당신은 그것을 할 수 있지만 완전히 자동으로 할 수는 없습니다.

사용자가 로그 아웃 링크를 클릭하고 로그인을 요청하는 일반 401과 동일한 영역 및 동일한 URL 폴더 레벨을 사용하여 응답으로 '401 Unauthorized'를 보내도록해야합니다.

다음에 잘못된 자격 증명을 입력하도록 지시해야합니다 (예 : 빈 사용자 이름과 비밀번호를 입력하면 "로그 아웃되었습니다"페이지가 나타납니다. 잘못된 / 빈 자격 증명은 이전의 올바른 자격 증명을 덮어 씁니다.

간단히 말해, 로그 아웃 스크립트는 로그인 스크립트의 논리를 반전시키고 사용자 올바른 자격 증명을 전달 하지 않은 경우에만 성공 페이지를 반환합니다 .

문제는 다소 호기심 많은 "비밀번호를 입력하지 마십시오"비밀번호 상자가 사용자의 승인을 충족시키는 지 여부입니다. 암호를 자동으로 채우려 고하는 암호 관리자도 여기에 들어갈 수 있습니다.

댓글에 대한 응답으로 추가하도록 수정 : 다시 로그인은 약간 다른 문제입니다 (두 단계의 로그 아웃 / 로그인이 분명하지 않은 경우). 재 로그인 링크에 대한 첫 번째 시도는 두 번째 시도 (다른 사용자 이름 / 암호가있는 것)를 수락하는 것보다 거부해야합니다 (401). 이를 수행 할 수있는 몇 가지 방법이 있습니다. 하나는 로그 아웃 링크에 현재 사용자 이름 (예 : / relogin? username)을 포함하고 자격 증명이 사용자 이름과 일치하면 거부합니다.


bobince의 답변에 추가 ...

Ajax를 사용하면 '로그 아웃'링크 / 버튼을 Javascript 기능에 연결할 수 있습니다. 이 함수가 잘못된 사용자 이름과 비밀번호로 XMLHttpRequest를 보내도록하십시오. 그러면 401이 다시 나타납니다. 그런 다음 document.location을 사전 로그인 페이지로 다시 설정하십시오. 이렇게하면 사용자는 로그 아웃하는 동안 추가 로그인 대화 상자를 볼 수 없으며 잘못된 자격 증명을 입력해야합니다.


사용자에게 https : // log : out@example.com/ 링크를 클릭하도록합니다 . 기존 자격 증명을 유효하지 않은 자격 증명으로 덮어 씁니다. 로그 아웃


당신은 완전히 JavaScript로 할 수 있습니다 :

IE는 기본 인증 캐시를 지우는 표준 API를 오랫동안 가지고 있습니다.

document.execCommand("ClearAuthenticationCache")

작동하면 true를 반환해야합니다. 다른 브라우저에서 false, undefined 또는 blow-up을 반환합니다.

새로운 브라우저 (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*/);


다음 기능은 Firefox 40, Chrome 44, Opera 31 및 IE 11에서 작동하는 것으로 확인되었습니다.
Bowser 는 브라우저 감지에 사용되며 jQuery도 사용됩니다.

-secUrl은 로그 아웃 할 비밀번호로 보호 된 영역의 URL입니다.
-redirUrl은 비밀번호로 보호되지 않은 영역의 URL입니다 (로그 아웃 성공 페이지).
-리디렉션 타이머 (현재 200ms)를 늘리고 싶을 수도 있습니다.

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);
}


다음은 jQuery를 사용하는 매우 간단한 Javascript 예제입니다.

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

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

이 사용자는 브라우저 로그인 상자를 다시 표시하지 않고 로그 아웃 한 다음 로그 아웃 된 페이지 로 리디렉션 합니다 .


기본 인증으로는 직접 가능하지 않습니다.

HTTP 사양에는 서버가 사용자에게 이미 제시 한 자격 증명 전송을 중지하도록 브라우저에 지시하는 메커니즘이 없습니다.

일반적으로 XMLHttpRequest를 사용하여 잘못된 자격 증명으로 HTTP 요청을 보내 원래 제공 한 자격 증명을 덮어 쓰는 "해킹"(다른 답변 참조)이 있습니다.


실제로는 매우 간단합니다.

브라우저에서 다음을 방문하여 잘못된 자격 증명을 사용하십시오. http : // username : password@yourdomain.com

"로그 아웃"해야합니다.


이것은 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"); 
      });
  });          

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;
}

 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;
}

로그 아웃 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>

이 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+'/';
}

이것을 응용 프로그램에 추가하십시오.

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

위에서 읽은 것을 기반으로 모든 브라우저에서 작동하는 간단한 솔루션을 얻었습니다.

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) 여러 가지 방법으로 로그 아웃 사용자를 허용하는 로그인 백엔드와 그렇지 않은 로그인 백엔드를 생성했습니다. 내 일반 로그인 페이지는 수락하지 않는 로그인 페이지를 사용하고, 내 로그 아웃 페이지는 승인 된 로그인 페이지를 사용합니다.


  • 세션 ID 사용 (쿠키)
  • 서버에서 세션 ID를 무효화
  • 유효하지 않은 세션 ID를 가진 사용자를 허용하지 마십시오

최신 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);
}


  
    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(); ?>

그러나 그것은 당신을 새로운 위치로 리디렉션합니다. 로그 아웃이 없습니다.


chrome://restart주소 표시 줄에 입력 하면 크롬이 백그라운드에서 실행되는 모든 앱과 함께 다시 시작되고 인증 비밀번호 캐시가 정리됩니다.


기록을 위해이라는 새로운 HTTP 응답 헤더가 Clear-Site-Data있습니다. 서버 응답에 Clear-Site-Data: "cookies"헤더가 포함 된 경우 쿠키뿐만 아니라 인증 자격 증명도 제거해야합니다. 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

참고 URL : https://stackoverflow.com/questions/233507/how-to-log-out-user-from-web-site-using-basic-authentication

반응형