django认证01---token
1.登录鉴权跟 Token 的鉴权区别
以 Django 的账号密码登录为例来说明传统的验证鉴权方式是怎么工作的,当我们登录页面输入账号密码提交表单后,会发送请求给服务器,服务器对发送过来的账号密码进行验证鉴权,验证鉴权通过后,把用户信息记录在服务器端( django_session 表中),同时返回给浏览器一个 sessionid 用来唯一标识这个用户,浏览器将 sessionid 保存在 cookie 中,之后浏览器的每次请求都一并将 sessionid 发送给服务器,服务器根据 sessionid 与记录的信息做对比以验证身份
Token 的鉴权方式就清晰很多了,客户端用自己的账号密码进行登录,服务端验证鉴权,验证鉴权通过生成 Token 返回给客户端,之后客户端每次请求都将 Token 放在 header 里一并发送,服务端收到请求时校验 Token 以确定访问者身份
session 的主要目的是给无状态的 HTTP 协议添加状态保持,通常在浏览器作为客户端的情况下比较通用。而 Token 的主要目的是为了鉴权,同时又不需要考虑 CSRF 防护以及跨域的问题,所以更多的用在专门给第三方提供 API 的情况下,客户端请求无论是浏览器发起还是其他的程序发起都能很好的支持。所以目前基于 Token 的鉴权机制几乎已经成了前后端分离架构或者对外提供 API 访问的鉴权标准,得到广泛使用
2.基于restframework 的用户验证跟 django 用户验证的区别
基于restframework 的用户验证跟 django 用户验证的区别 : django 用户验证只是基于 cookie 与 session 来完成的。而restframework还可以通过token
其中的问题就在于中间件的差距。 我现在访问我的 restf api 接口时可以看到浏览器会有一个登陆 ,这里通过 django 创建的 超级用户或者注册的用户就可以登陆 这是因为我们在 django 的url 中配置了 url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), 而 对应的 rest_framework.urls 有 包含 login 和 logout 两个url。 如果使用django会验证 csrf ,我们登陆时 django 返回的 html 中其实是包含一个 csrf 的 code 的,用来做表单的 安全验证的。(这是因为django默认打开 csrf 中间件,如果关闭了就不会校验csrf)
所以如果用户验证需要做成 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 是没有过期时间的,永久有效,一旦泄露了别人就可以一直用。
2 django中实现token:引入DRF 框架
注意DRF框架是基于django,也就是说使用DRF包就必须安装django。所以文件结构和django一样,可以混用:既开发django也开发djangorestframework。
setting中的配置:REST框架API的任何全局设置都保存在一个名为REST framework的配置字典中。与django不冲突。
当我们用浏览器访问rest_framework 的应用时REST framework的配置生效,而我们访问我们正常的django的app时django的配置生效。注意这里都是全局配置
尤其是对应中间件的配置,和项目目录下的url文件息息相关。
正常情况下我们会引入:
'rest_framework',而我们现在只需要认证功能 rest_framework.authtoken
在配置中加入TokenAuthentication,也就是通过token 我们就可以直接从request 中取出user(这就是中间件的好处)取出user意味着登陆状态
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ) }
setting文件 REST_FRAMEWORK 配置:https://www.django-rest-framework.org/ (中间件)
DEFAULT_AUTHENTICATION_CLASSES 身份验证类的列表或元组,用于确定访问request.user或request.auth属性时使用的默认验证器集。 默认: ( 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication' )
DEFAULT_PERMISSION_CLASSES 权限类的列表或元组,用于确定在视图开头检查的默认权限集。必须由列表中的每个类授予权限。
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
'rest_framework.permissions.IsAdminUser',(仅管理员可以访问DRF的所有url)
'rest_framework.permissions.IsAuthenticated', #必须有(必需认证过才能访问DRF所有url)
默认:
( 'rest_framework.permissions.AllowAny', )
PAGE_SIZE
用于分页的默认页面大小。如果设置为None
,则默认情况下禁用分页。
使用:
配置所有,
sender指定settings.AUTH_USER_MODEL
设置每次新生成用户时,自动生成token的signals。
from django.conf import settings from django.db.models.signals import post_save from django.dispatch import receiver from rest_framework.authtoken.models import Token # 为每个用户添加token验证 @receiver(post_save, sender=settings.AUTH_USER_MODEL) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance)
.__init__.py 将它放在models.py文件中的任何地方,它将在Django线程启动时注册(__init__.py也是可以的)
from .signals import create_auth_token
sender指定实体
from django.contrib.auth.models import User
@receiver(post_save, sender=User) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance)
在view中进行token验证
没有就创建并且取出token,有就直接取出token
token, created = Token.objects.get_or_create(user=user)
虽然在django设置文件中指定了REST_FRAMEWORK设置,但是基于函数的视图需要@api_view装饰器,否则,根本不执行令牌认证
django自带app和django_rest_framework的区别:
from rest_framework.decorators import api_view @api_view(['POST','GET']) def my_view(request): if request.user.is_authenticated(): ...
过期时间:
https://www.cnblogs.com/hello-/articles/9090786.html
https://www.jianshu.com/p/078fb116236e
3.django中实现:JWT