6

我正在设计一个网站,人们将在其中以用户身份登录,并可能在多个组中,这些组有几种不同的类型。我既想拥有一个人们可以直接使用的网站,又想公开一个可供其他网站使用的 API。

什么是实现登录系统的最佳方法,该系统既适用于网站本身的普通用户,又允许使用 API 的网站代表用户无缝创建帐户并允许用户从我的网站查看他们的数据网站和使用 API 的网站?

我使用的是 Django 1.5,所以我愿意自定义用户模型等等。API 将使用 Tastypie 提供。

编辑:老实说,我的主要问题是我并不真正了解 API 密钥何时有用以及它们如何与常规用户登录共存(如果有的话)。

4

3 回答 3

11

Use case:

The first and use case for API keys is automation. You provide your api key (or commonly called token) to a 3rd party and voila, you can have the 3rd party do stuff for you. When you do not trust the 3rd party anymore, you can just revoke the api key or re-generate it. Api keys allow the user to initiate & authenticate the chain of actions by requesting the token via traditional authentication (e.g username/password), and then the user passes it on to the interested parties. See my little story about phone numbers at the end.

Why not use passwords?

Because you don't want to compromise your users on other websites and have them type their password there in order to use your APIs. If the 3rd party is compromised, then the user's communications or password are compromised.

Here are good resources:


Api keys with tastypie

Here is a good starting point:

from django.contrib.auth.models import User
from django.db import models
from tastypie.models import create_api_key
models.signals.post_save.connect(create_api_key, sender=User)

This should take care of creating api keys thanks to the post_save signal. The second part is to allow more than one scheme for the authentication to fit your use case, so... onto MultiAuthentication:

from django.contrib.auth.models import User
from tastypie.authentication import BasicAuthentication, ApiKeyAuthentication, MultiAuthentication
from tastypie.authorization import DjangoAuthorization
from tastypie.resources import ModelResource

class UserResource(ModelResource):
    class Meta:
        queryset = User.objects.all()
        resource_name = 'auth/user'
        excludes = ['email', 'password', 'is_superuser']

        authentication = MultiAuthentication(BasicAuthentication(), ApiKeyAuthentication())
        authorization = DjangoAuthorization()

Other considerations

These are good practice to never leak sensitive data on the network:

  • do not do any user/password authentication without ssl or tls.
  • never use http basic authentication without ssl or tls.
  • lock down resources users shouldn't access to with permissions.
  • make sure your responses have correct cache-control headers
  • always allow users to reset/regenerate/delete their tokens / api keys.
  • a user need not have only one api key, you can have several of them; one for each 3rd party.

I use gmail so here is an example from https://security.google.com/settings/security (review permissions) where I can see how google openid is used:

revoking permissions for google openid

Why should you use one api key for each 3rd party? is the same as why should you allow the user to have more than one api key and label them for a particular use?.

The answer is that if the api key is something you share just like your phone number, but you don't need to give the same phone number to all your friends (google voice FTW!).

  • case 1: one phone number.

If your friend misbehaves and gives it to a bunch of sales rep, you are going to be pretty annoyed. If your phone is the same, then whoever has it may share it with somebody else without your knowing. End results, all sales reps know your number... not so good. But you still want your mom to be able to call you, right? So you can't really change your number. Now imagine a more dangerous situation; you have a tab at the local pizzeria, and they know you by name / phone number. If someone gets your api key, they may impersonate you to order pizza and still charge you (you have a tab!).

  • case 2: multiple phone numbers:

If you have 100 numbers to you give to 100 different friends, not only can they contact you, but if a sales rep calls you on a particular number, you would know which of your friend gave it away and you can just cut that one number. Mom's now happy because she can tell you where to go for brunch. Your friend now decides to order pizza ... you can now trace it to your friend (or you should provide the pizzeria a number that none of your friend knows).

于 2013-07-14T22:04:35.293 回答
0

我会设计系统,使每个请求都需要有一个 API 密钥。理想情况下,您将其放在Authorization每个请求的标头中。API 应该尽可能纯 RESTFul,即没有会话处理。我认为这对于良好的 API 设计非常重要。

完成该部分后,您的用户将以完全相同的方式访问该站点。但是,他们不会记住他们的 API 密钥,而只会记住他们的凭据。因此,有一个登录页面,根据用户的凭据对用户进行身份验证,然后返回要存储在客户端会话中的 api 密钥。从那时起,所有请求都应使用 API 密钥进行授权。

于 2013-07-17T12:22:50.687 回答
0

从安全的角度来看,“API 密钥”主要有两类,每类都有不同的用途:

  • 一个随机的 API 密钥,其作用类似于密码和用户名的组合:它被硬连线到客户端配置文件中,并被视为机密。只需拥有此密钥,您就可以访问 API。因为密钥代表识别客户端的秘密(从而验证信任),所以必须随每个请求传输该秘密。连接必须是可信的,以确保机密不会被截获,这意味着所有 API 访问都必须需要 TLS/SSL。通常这种方法通过仅在第一个请求上使用密钥来扩展,其余的连接使用链接到客户端 IP 地址的旋转会话密钥执行(很像在网站上登录)
  • 非对称签名方案:DSA 或 RSA 等非对称密码用于创建存储在客户端配置中的密钥。秘密永远不会在网络上共享,而是加密每个 API 请求的哈希值。服务器保留一个公钥链接到每个私钥,该私钥解密每个请求的散列签名,然后创建自己的请求散列以进行验证。这是执行 API 身份验证的推荐和理想方式,因为它不需要 TLS/SSL 并且不需要会话管理策略。

我不知道 django 的 API 身份验证库,建议查看 Amazon AWS 的基于 HMAC 非对称签名方法的源代码,以获得出色的实施。

于 2013-07-16T19:53:57.713 回答