如何用PHP进行单点登录?

Egg*_*abs 20 php

例如:使用单个Google帐户的Gmail,Orkut,Wava和feedburner登录访问权限.

Nic*_*ico 76

你的问题太具体了,不能给出准确的答案.如果您尝试让用户使用Google帐户登录您的网站,请在此处进行说明.

另一方面,如果您尝试让用户使用一个帐户登录您控制的多个网站,请按以下步骤操作:

使您站点上的所有登录链接指向集中登录页面,但包括有关用户来自链接的位置的信息.例如:

<a href='http://login.example.com/login.php?source=my.other.site.com/foo/bar'>log in!!</a>
Run Code Online (Sandbox Code Playgroud)

然后,一旦用户成功登录,您就会将用户重定向回原始站点,同时传递有关经过身份验证的用户所需的任何信息.

但是,您还需要确保人们不能通过向URL添加必要的身份验证参数来绕过您的身份验证机制.这可以通过以参数的HMAC-SHA-256形式包括签名以及存储在登录服务器和始发站点上的秘密来完成.(对于使用SSO系统的每个站点,此密钥最好不同.)

<?php
$MySecretKey = 'Nobody Will Ever Guess This!!';

// Generate signature from authentication info + secret key
$sig = hash(
    'sha256',
     $user->id . $user->email,
     $MySecretKey
);

// Make sure we're redirecting somewhere safe
$source = parse_url($_GET['source']);
if(in_array($source->host, $list_of_safe_hosts))
  $target = 'http://'.$source->host.$source->path;

// Send the authenticated user back to the originating site
header('Location: '.$target.'?'.
    'user_id='.$user->id.
    '&user_email='.urlencode($user->email).
    '&sig='.$sig);
?>
Run Code Online (Sandbox Code Playgroud)

然后,在原始站点中,如果签名匹配,则用户已登录.将有关登录用户的信息存储在会话变量(不是cookie)中:

<?php
$MySecretKey = 'Nobody Will Ever Guess This!!';

// Set not logged in by default
$user_id = 0;
$user_email = '';

if(intval($_GET['user_id']) && !$_SESSION['user_id']) // Someone trying to log in?
{
  // See if they have the right signature
  if (hash_equals(hash('sha256', intval($_GET['user_id']).$_GET['user_email'], $MySecretKey), $sig)) {
    $_SESSION['user_id'] = intval($_GET['user_id']);
    $_SESSION['user_email'] = $_GET['user_email'];
  }
}

?>
Run Code Online (Sandbox Code Playgroud)

请注意,我正在使用PHP 5.6中添加的功能:hash_equals.如果低于5.6,则可以使用此替换函数,该函数使用双HMAC验证实现计时安全比较功能:

function hash_equals($a, $b) {
    $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
    return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);
}
Run Code Online (Sandbox Code Playgroud)

这显然是一个非常粗略的实施,但它应该是一个不错的起点.

  • 我实际上意味着它是粗糙的,因为我在这里编写代码而没有任何测试.考虑到原始问题中完全缺乏细节,我认为我的答案超出了预期的范围.那就是说,是的,你指出的问题肯定是有效的. (14认同)
  • 如果它“显然非常粗糙”,那么如果您列出当前的安全缺陷以及实际的实现应如何解决该缺陷,那就太好了。例如:网络嗅探 $sig 的问题、使用同一帐户多次登录等等。 (2认同)
  • $ MySecretKey ='没有人会猜到这个!!'; 如果它是一个常量,有人可以观察并知道每次我们在末尾附加一些相同的代码.那么它是如何安全的? (2认同)
  • @aparna客户端从未见过秘密本身,它仅用于生成无法在不知道秘密的情况下进行预测的MD5哈希.此外,它不一定需要保持不变,但是两个服务器都需要能够确定任何特定登录尝试的秘密,而不需要查看传输中包含的任何内容. (2认同)

xaa*_*aav 7

如果您想要跨站点中央登录系统,我会推荐像OpenID这样的东西.您可以运行自己的服务器,然后只有一个登录多个站点.

  • @Maruccio:与SSO不同的是,你登录一次 - 因此得名.OpenID允许您在多个站点上使用相同的ID,但这并不意味着您登录到一个站点时都会登录到它们. (3认同)