Django单点登录和Php站点:跨域登录?

时间:2022-08-23 10:50:15

I am building a small app as a service in django and now is the time to integrate it on some clients PHP web app.

我正在django中构建一个小应用程序作为服务,现在是时候将它集成到一些客户端PHP Web应用程序上。

Our client A from domain www.a.com handles his own authentication for his users and probably use cookies for sessions.

我们的域名www.a.com的客户A为其用户处理自己的身份验证,并可能使用Cookie进行会话。

How could i make logged in users from his domain also logged in on my Django app dommain www.b.com/clientA/ ?

我如何从他的域中登录用户也登录我的Django应用程序dommain www.b.com/clientA/?

I see how i can make them reloggin on my domain and use an authbackend checking credential with domain A but that means the user will have to enter his login/pass twice: on www.a.com and www.b.com.

我知道如何让我们在我的域上重新登录并使用域名A的authbackend检查凭证,但这意味着用户必须输入他的登录/通行证两次:在www.a.com和www.b.com上。

Accessing cookie from domain www.a.com is impossible for security reasons i think.

出于安全考虑,我认为从域www.a.com访问cookie是不可能的。

How would you handle this ?

你会怎么处理这个?

4 个解决方案

#1


You are correct in assuming cookies from another domain cannot be accessed. However, if it's on a subdomain, you should be able to access the cookies if they're set correctly.

假设无法访问来自其他域的cookie,您是正确的。但是,如果它位于子域中,则应该能够在正确设置cookie时访问它们。

If you absolutely must have them on completely separate domains, it's going to be a bit tricky. If you can't modify the existing PHP code, you can pretty much forget it.

如果你绝对必须在完全独立的域上拥有它们,那将会有点棘手。如果你不能修改现有的PHP代码,你几乎可以忘记它。

One option would be using OpenID - that may be the simplest way to tackle this, as there are OpenID libraries available for PHP and Python. OpenID would allow you to have a single-sign on like authentiction, and since it's already used on various sites it is proven and works.

一种选择是使用OpenID - 这可能是解决这个问题的最简单方法,因为有可用于PHP和Python的OpenID库。 OpenID将允许您像真实一样进行单点登录,并且由于它已经在各种站点上使用,因此它已被证明并且有效。

Another option is writing a custom single sign-on system.

另一种选择是编写自定义单点登录系统。

The basic idea is that when a user arrives at your site, you direct them to a login site. This can be either in the PHP or Python end of things, or separate. Here, the user will sign in, and then the login generates a secret key - this can be a hash, random string, whatever as long as it's not predictable - and the user is redirected back to the main site with the key.

基本的想法是,当用户到达您的站点时,您将他们引导到登录站点。这可以是PHP或Python的结尾,也可以是单独的。在这里,用户将登录,然后登录生成一个密钥 - 这可以是一个哈希,随机字符串,只要它是不可预测的 - 然后用密钥将用户重定向回主站点。

The main site then sees the user has a key, and sends a request to the login site behind the scenes to verify the user's key.

然后,主站点看到用户有一个密钥,并在后台向登录站点发送请求以验证用户的密钥。

Now the user is logged in at one site. When the user visits the second site, it too redirects the user to the login site. Since the user had already logged in, the login site simply redirects the user back with a new secret key, and the second site verifies it from the login site and now the user is logged in without having to input their credentials another time.

现在,用户已在一个站点登录。当用户访问第二个站点时,它也会将用户重定向到登录站点。由于用户已经登录,因此登录站点仅使用新密钥重定向用户,并且第二站点从登录站点验证它,现在用户登录而无需再次输入其凭证。

#2


Ok, this is how to authenticate a Django user from PHP, or how to "read" a Django password from PHP.

好的,这是如何从PHP验证Django用户,或如何从PHP“读取”Django密码。

I think OpenID is the best solution but I had to authenticate Django users in a PHP app sharing the same database today and this is how I solved:

我认为OpenID是最好的解决方案,但是我必须在今天共享相同数据库的PHP应用程序中验证Django用户,这就是我解决的问题:

<?php

/* Generates crypted hash the same way as Django does */
function get_hexdigest($algorithm, $salt, $raw_password) {
   if (!array_in($algorithm, array('md5', 'sha1'))) {
       return false;
   }
   return $algorithm($salt.$raw_password);
}

/* Checks if password matches the same way Django does */
function check_password($raw_password, $django_password) {
    list($algorithm, $salt, $hsh) = explode('$', $django_password);
    return get_hexdigest($algoritm, $salt, $raw_password) === $hsh;
}

?>

The key is to understand the format in which Django saves the passwords, which is:

关键是要了解Django保存密码的格式,即:

[algorithm]$[salt]$[hash]

So for example I had an "admin" user with password "admin" and the password field in the auth_user row was:

例如,我有一个“admin”用户,密码为“admin”,auth_user行中的密码字段为:

sha1$63a11$85a93f217a72212b23fb0d5b95f3856db9575c1a

The algorithm is "sha1", the salt, which was generated randomly is "63a11" and the crypted hash is "85a93f217a72212b23fb0d5b95f3856db9575c1a".

该算法是“sha1”,随机生成的盐是“63a11”,加密的散列是“85a93f217a72212b23fb0d5b95f3856db9575c1a”。

So who do you produce the crypted hash in PHP? You simple concatenate the salt and the raw password and hash it with the algorithm, in this case, sha1:

那么你是谁在PHP中生成加密的哈希?您可以简单地连接salt和原始密码并将其与算法一起散列,在本例中为sha1:

<?php 

$salt = '63a11';
$pass = 'admin';

echo sha1($salt.$admin); // prints "85a93f217a72212b23fb0d5b95f3856db9575c1a"

?>

That wasn't difficult! I got it by reading the relevant code in the Django sources.

那不难!我通过阅读Django源代码中的相关代码得到了它。

#3


You can use HTTP redirects back and forth. When the user accesses www.b.com, and no cookie is set, redirect to www.a.com/crosslogin?return_to=URL&challenge=stuff. On a.com, check for the cookie, and if it is set, redirecto to URL?verified=otherstuff.

您可以来回使用HTTP重定向。当用户访问www.b.com并且未设置cookie时,请重定向到www.a.com/crosslogin?return_to=URL&challenge=stuff。在a.com上,检查cookie,如果已设置,则重定向到URL?verified = otherstuff。

This would require challenge-response cryptography if you want users to prevent from faking authentication. a.com and b.com would need to setup a shared secret, and stuff is encrypted with that secret. otherstuff is also encrypted with that secret; when decrypted, it gives a tuple (stuff, user). b.com may need to keep a replay cache to make sure that otherstuff can be used only once.

如果您希望用户防止伪造身份验证,则需要质询 - 响应加密。 a.com和b.com需要设置共享密钥,并使用该秘密加密内容。 otherstuff也用这个秘密加密;当解密时,它给出一个元组(东西,用户)。 b.com可能需要保留重播缓存以确保其他缓存只能使用一次。

#4


I see the following options:

我看到以下选项:

1) Use Open ID as Jani Hartkainen suggested. It could be the best solution.

1)使用Open ID,Jani Hartkainen建议。这可能是最好的解决方案。

2) Use one domain via http reverse proxy:

2)通过http反向代理使用一个域:

Use reverse http proxy to put both php application and your django application on the same domain. This would give you access to the sessions cookies of your php app.

使用反向http代理将php应用程序和django应用程序放在同一个域中。这将使您可以访问您的PHP应用程序的会话cookie。

Once you get the php session id in your django application run a request to the PHP application with the session cookie set to check who is logged in. Unfortunately this may require html scraping or implementing a simple service in PHP application that would return a name of the logged in user. Once you get the logged in user you can authorize it in your django app.

一旦你在django应用程序中获得了php会话id,就会向PHP应用程序运行一个请求,并设置会话cookie以检查谁登录。不幸的是,这可能需要在PHP应用程序中使用html抓取或实现一个简单的服务,该服务将返回一个名称登录用户。获得登录用户后,您可以在django应用程序中对其进行授权。

3) PHP session id passed via GET:

3)通过GET传递的PHP会话ID:

Modify the PHP app to add session id as a parameter to links to your django app. For example ask clients to refer to your web site as follows:

修改PHP应用程序以将会话ID添加为链接到django应用程序的参数。例如,要求客户引用您的网站,如下所示:

<yourwebsite.com>/?client_session_id=<session_id>&client_name=<client_name>

Once you get the session id you can authenticate user as described in point 2.

获得会话ID后,您可以按照第2点中的说明对用户进行身份验证。

#1


You are correct in assuming cookies from another domain cannot be accessed. However, if it's on a subdomain, you should be able to access the cookies if they're set correctly.

假设无法访问来自其他域的cookie,您是正确的。但是,如果它位于子域中,则应该能够在正确设置cookie时访问它们。

If you absolutely must have them on completely separate domains, it's going to be a bit tricky. If you can't modify the existing PHP code, you can pretty much forget it.

如果你绝对必须在完全独立的域上拥有它们,那将会有点棘手。如果你不能修改现有的PHP代码,你几乎可以忘记它。

One option would be using OpenID - that may be the simplest way to tackle this, as there are OpenID libraries available for PHP and Python. OpenID would allow you to have a single-sign on like authentiction, and since it's already used on various sites it is proven and works.

一种选择是使用OpenID - 这可能是解决这个问题的最简单方法,因为有可用于PHP和Python的OpenID库。 OpenID将允许您像真实一样进行单点登录,并且由于它已经在各种站点上使用,因此它已被证明并且有效。

Another option is writing a custom single sign-on system.

另一种选择是编写自定义单点登录系统。

The basic idea is that when a user arrives at your site, you direct them to a login site. This can be either in the PHP or Python end of things, or separate. Here, the user will sign in, and then the login generates a secret key - this can be a hash, random string, whatever as long as it's not predictable - and the user is redirected back to the main site with the key.

基本的想法是,当用户到达您的站点时,您将他们引导到登录站点。这可以是PHP或Python的结尾,也可以是单独的。在这里,用户将登录,然后登录生成一个密钥 - 这可以是一个哈希,随机字符串,只要它是不可预测的 - 然后用密钥将用户重定向回主站点。

The main site then sees the user has a key, and sends a request to the login site behind the scenes to verify the user's key.

然后,主站点看到用户有一个密钥,并在后台向登录站点发送请求以验证用户的密钥。

Now the user is logged in at one site. When the user visits the second site, it too redirects the user to the login site. Since the user had already logged in, the login site simply redirects the user back with a new secret key, and the second site verifies it from the login site and now the user is logged in without having to input their credentials another time.

现在,用户已在一个站点登录。当用户访问第二个站点时,它也会将用户重定向到登录站点。由于用户已经登录,因此登录站点仅使用新密钥重定向用户,并且第二站点从登录站点验证它,现在用户登录而无需再次输入其凭证。

#2


Ok, this is how to authenticate a Django user from PHP, or how to "read" a Django password from PHP.

好的,这是如何从PHP验证Django用户,或如何从PHP“读取”Django密码。

I think OpenID is the best solution but I had to authenticate Django users in a PHP app sharing the same database today and this is how I solved:

我认为OpenID是最好的解决方案,但是我必须在今天共享相同数据库的PHP应用程序中验证Django用户,这就是我解决的问题:

<?php

/* Generates crypted hash the same way as Django does */
function get_hexdigest($algorithm, $salt, $raw_password) {
   if (!array_in($algorithm, array('md5', 'sha1'))) {
       return false;
   }
   return $algorithm($salt.$raw_password);
}

/* Checks if password matches the same way Django does */
function check_password($raw_password, $django_password) {
    list($algorithm, $salt, $hsh) = explode('$', $django_password);
    return get_hexdigest($algoritm, $salt, $raw_password) === $hsh;
}

?>

The key is to understand the format in which Django saves the passwords, which is:

关键是要了解Django保存密码的格式,即:

[algorithm]$[salt]$[hash]

So for example I had an "admin" user with password "admin" and the password field in the auth_user row was:

例如,我有一个“admin”用户,密码为“admin”,auth_user行中的密码字段为:

sha1$63a11$85a93f217a72212b23fb0d5b95f3856db9575c1a

The algorithm is "sha1", the salt, which was generated randomly is "63a11" and the crypted hash is "85a93f217a72212b23fb0d5b95f3856db9575c1a".

该算法是“sha1”,随机生成的盐是“63a11”,加密的散列是“85a93f217a72212b23fb0d5b95f3856db9575c1a”。

So who do you produce the crypted hash in PHP? You simple concatenate the salt and the raw password and hash it with the algorithm, in this case, sha1:

那么你是谁在PHP中生成加密的哈希?您可以简单地连接salt和原始密码并将其与算法一起散列,在本例中为sha1:

<?php 

$salt = '63a11';
$pass = 'admin';

echo sha1($salt.$admin); // prints "85a93f217a72212b23fb0d5b95f3856db9575c1a"

?>

That wasn't difficult! I got it by reading the relevant code in the Django sources.

那不难!我通过阅读Django源代码中的相关代码得到了它。

#3


You can use HTTP redirects back and forth. When the user accesses www.b.com, and no cookie is set, redirect to www.a.com/crosslogin?return_to=URL&challenge=stuff. On a.com, check for the cookie, and if it is set, redirecto to URL?verified=otherstuff.

您可以来回使用HTTP重定向。当用户访问www.b.com并且未设置cookie时,请重定向到www.a.com/crosslogin?return_to=URL&challenge=stuff。在a.com上,检查cookie,如果已设置,则重定向到URL?verified = otherstuff。

This would require challenge-response cryptography if you want users to prevent from faking authentication. a.com and b.com would need to setup a shared secret, and stuff is encrypted with that secret. otherstuff is also encrypted with that secret; when decrypted, it gives a tuple (stuff, user). b.com may need to keep a replay cache to make sure that otherstuff can be used only once.

如果您希望用户防止伪造身份验证,则需要质询 - 响应加密。 a.com和b.com需要设置共享密钥,并使用该秘密加密内容。 otherstuff也用这个秘密加密;当解密时,它给出一个元组(东西,用户)。 b.com可能需要保留重播缓存以确保其他缓存只能使用一次。

#4


I see the following options:

我看到以下选项:

1) Use Open ID as Jani Hartkainen suggested. It could be the best solution.

1)使用Open ID,Jani Hartkainen建议。这可能是最好的解决方案。

2) Use one domain via http reverse proxy:

2)通过http反向代理使用一个域:

Use reverse http proxy to put both php application and your django application on the same domain. This would give you access to the sessions cookies of your php app.

使用反向http代理将php应用程序和django应用程序放在同一个域中。这将使您可以访问您的PHP应用程序的会话cookie。

Once you get the php session id in your django application run a request to the PHP application with the session cookie set to check who is logged in. Unfortunately this may require html scraping or implementing a simple service in PHP application that would return a name of the logged in user. Once you get the logged in user you can authorize it in your django app.

一旦你在django应用程序中获得了php会话id,就会向PHP应用程序运行一个请求,并设置会话cookie以检查谁登录。不幸的是,这可能需要在PHP应用程序中使用html抓取或实现一个简单的服务,该服务将返回一个名称登录用户。获得登录用户后,您可以在django应用程序中对其进行授权。

3) PHP session id passed via GET:

3)通过GET传递的PHP会话ID:

Modify the PHP app to add session id as a parameter to links to your django app. For example ask clients to refer to your web site as follows:

修改PHP应用程序以将会话ID添加为链接到django应用程序的参数。例如,要求客户引用您的网站,如下所示:

<yourwebsite.com>/?client_session_id=<session_id>&client_name=<client_name>

Once you get the session id you can authenticate user as described in point 2.

获得会话ID后,您可以按照第2点中的说明对用户进行身份验证。