基于restframework 的用户验证跟 django 用户验证的区别 :
django 用户验证只要是基于 cookie 与 session 来完成的。
我现在访问我的 restf api 接口时可以看到浏览器会有一个登陆 ,这里通过 django 创建的 超级用户
或者注册的用户就可以登陆
这是因为我们在 django 的url 中配置了
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
而 对应的 rest_framework.urls 有 包含 login 和 logout 两个url。
这里会让登陆验证变得很简单,但是 他会验证 csrf ,我们登陆时 django 返回的 html 中其实是
包含一个 csrf 的 code 的,用来做表单的 安全验证的。
所以
如果用户验证需要做成 restful api ,这个 自带的 login是无法拿来直接用的。
那如果我们需要做成一个前后端分离的用户验证, 就需要通过其他的方法。 【Auth 模块】
django 的 MIDDLEWARE 中包含的以下两个 MIDDLEWARE
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
可以在一个 request 进来的时候,将request里的 cookie 里面的 session_id 转换成
我们的 user !!!!! 也就是我们之前看到的 request.user 。
我们现在需要配置 restful 的 MIDDLEWARE , 直接在 django 的 settings.py 里面添加
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)
}
官方文档显示 restful 提供的 auth 有三种 :
BasicAuthentication 、 TokenAuthentication 、 SessionAuthentication 。
其中 :
SessionAuthentication :跟django中的机制是一样的, 常用于浏览器,
因为浏览器会自动设置 cookie ,并将他的 cooike 和session 带到服务器,
所以前后端分离的系统用这种机制比较少见,但是还是可以做。
TokenAuthentication : 是需要重点关注的,使用他前 ,必须先将 'rest_framework.authtoken'
添加到 django 的 INSTALLED_APPS 中。
INSTALLED_APPS = ( ... 'rest_framework.authtoken' )
这个 tokenauth 实际上会给我们创建一张表,凡是有表的 app 都要加入到 INSTALLED_APPS 中。
如果不加人,就不会帮我们生成这些表。
此时执行 migrate 进行数据迁移。
可以看到为我们生成了一张表,该表有一个外键指向我们的 UserProfile (用户信息)表。
一个用户对于一个 token 。
而我创建一个超级用户的时候,并没有在 authtoken_token 这张表里面给我添加一个对应的 token 。
这个 token 需要我们自己来创建 。创建方法如下 ,调用 Token 模块,将 user 传进去:
from rest_framework.authtoken.models import Token token = Token.objects.create(user=...) print token.key
所以 当用户注册时保存了提交的 UserProfile 之后,调用这段代码,把保存的 UserProfile 传进去。
这样就会生成 token 。
---------------------------------
而后端需要在 django 的 url 中配置 token 的url :
from rest_framework.authtoken import views urlpatterns += [ url(r'^api-token-auth/', views.obtain_auth_token) ]
现在可以通过向 http://127.0.0.1:8000/api-token-auth/ 这个url 发送 post 请求并且携带
{
"username":"admin",
"password":"admin123456"
}
这个方式来获取 token ,发送请求后,他会返回一个 token 。此时如果这个 UserProfile
没有对应的 key ,就会在 authtoken_token 这张表创建一条数据 ,并且关联到你提交的
用户 ,给他生成一个 key 。
前端如何使用这个 token ? 【把他放到 http 的 header 里面】
对于客户端进行身份验证,令牌密钥应该包含在AuthorizationHTTP头中。关键字应以字符串文字“Token”为前缀,用空格分隔两个字符串。例如:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
此时我在我的 url 请求的头部添加这个之后,访问我的 restful api 资源了后台获取到这个 token 后
还不能解析出这个 token 对应的用户是谁,我们需要在 REST_FRAMEWORK 里添加
'rest_framework.authentication.TokenAuthentication',
才能解析出对应的用户 。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
)
}
此时需要知道用户传递过来的 token 是什么 ,直接通过 request.auth 就可以看到。
完成 上面两步,就可以访问我的 restful api 资源了。
(以前需要登录,现在只要头部包含 这个 token 就可以访问。)
如果用户在 token 过期的情况下访问公共url , 就会报错, 这个问题前端也可以解决,后端的解决方案是, 把这个 token 验证不放在 settings.py 里做全局验证, 只对部分接口做验证。
把 REST_FRAMEWORK 中下面这个
1. 'rest_framework.authentication.TokenAuthentication',
注释掉 ,
2.在需要做验证的视图那里 导入
from rest_framework.authentication import TokenAuthentication
然后在视图里添加 authentication_classes 属性。 因为要给他个元组, 所以记得用逗号
authentication_classes = (TokenAuthentication, )
这个 token 的缺点是 :
1.这个token 是保存在服务器里面的。
如果我们是一个分布式系统,有两套子系统想要使用同一个认证系统,他就会出现问题,
因为他的 token 是放在某一台服务器的,如果是分布式的,那我们还得将这些用户同步过去。
2.这个 toen 是没有过期时间的,永久有效,一旦泄露了别人就可以一直用。