#验证登录传递的数据是否符合规则,forms
### forms.py ###
# 不能用ModelForm
# 登录要验证什么? username password
class LoginForm(forms.Form,tools.ErrorFormat): #ErrorFormat--优化error返回的错误信息 '''登陆验证username,password''' username = forms.CharField(min_length=5,max_length=20,required=True) password = forms.CharField(min_length=6,max_length=20,required=True) def clean(self): print("self.errors",self.errors) print("self.cleaned_data",self.cleaned_data) if not self.errors: #继续验证账号密码是否正确 username = self.cleaned_data['username'] password = self.cleaned_data['password'] #用户是否存在 qs = models.User.objects.filter(phone=username) if qs: user_obj = qs.first() if user_obj.check_password(password): self.cleaned_data['user'] =user_obj return self.cleaned_data else: self.add_error('password', '密码错误') else: self.add_error('username','用户不存在') return self.cleaned_data
##### tools.py ###
class ErrorFormat:
@property
def error_format(self):
errors_data = self.errors.get_json_data()
print("errors_data",errors_data)
error_list = []
for k,v in errors_data.items():
error_list.append(k+':'+v[0].get("message"))
return ','.join(error_list)
#2-views中写接口逻辑,连接并写入redis
class Login(View): def post(self, request): ''' 1、验证前端传递的数据是否符合规则,forms 2、登录成功需要有标示,标示(token)存到 redis :param request: :return: ''' form_obj = forms.LoginForm(request.POST) if form_obj.is_valid(): # 验证通过的数据 代表登录成功 # 登录成功需要有标示,标示(token)存到 redis form_data = form_obj.cleaned_data # token 生成方式 用户名 + 时间戳 + MD5 username = form_data.get('username') tmp_token = '%s%s' % (username, time.time()) # md5 用 tools提供工具 token = tools.md5(tmp_token) # 存 token的时候 token 应该key user = form_obj.cleaned_data['user'] # 安装 pip install django-redis # 获取redis 链接 默认取配置文件中 default redis = django_redis.get_redis_connection() # 参数1 是key 参数2 是value 参数3 是过期时间 单位秒 # {token:userobj} # pickle.dumps(user) 序列化数据,转成 二进制 redis.set(const.SESSION + token, pickle.dumps(user), const.EXIT_TIME) return NbResponse(token=token, user=user.name, user_id=user.id) else: return NbResponse(-1, form_obj.error_format)
### redis配置,setting###
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
"PASSWORD": "dsx", # 密码
# 这个redis是返回数据是bytes类型的,登录的时候user用pickle序列化的,存的是二进制,取出来的也是二进制
}
},
"redis2": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://118.24.3.40:6379/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100, 'decode_responses': True},
# 这个redis配置,从redis里面取到数据后会自动转成字符串,不是bytes类型
"PASSWORD": "HK139bc&*", # 密码
}
}
}
#3-NbResponse对响应数据封装 ,等同于重写JsonResponse
from django.http import JsonResponse class NbResponse(JsonResponse): def __init__(self, code=200, msg='操作成功', **kwargs): data = {"code": code, "msg": msg} data.update(kwargs) super().__init__(data=data, json_dumps_params={"ensure_ascii": False})
#4-ursl配置
### 其它接口登录校验token,中间件
class SessionMiddleware(MiddlewareMixin): # 增加 一个过滤的场景 # 预制一个 列表 列表用于存储,那些接口可以不登录就访问 setting中 :NO_LOGIN_LIST = ['login','register'] def check_url(self, path_info): for url in NO_LOGIN_LIST: # path_info 前端过来的路径 /api/login # url NO_LOGIN_LIST login if url in path_info: # 当前访问的接口路径 在 NO_LOGIN_LIST 返回false 不做token验证 return False return True def process_request(self, request): '''请求过来之后先走到的这里''' # print("dir(request)",dir(request)) # 前端传递过来的token 会自动变成大写,并且在前面增加HTTP # print("request.META.get('HTTP_TOKEN')",request.META.get('HTTP_TOKEN')) print('request.path_info', request.path_info) if self.check_url(request.path_info): token = request.META.get('HTTP_TOKEN') if token: redis = django_redis.get_redis_connection() b_data = redis.get(const.SESSION + token) if b_data: data = pickle.loads(b_data) # 将当前的登录信息 存储到request当中 request.user = data request.user_id = data.id request.token = token else: return NbResponse(-1, '请登录') else: return NbResponse(-1, '请登录')
##登出,删除token
class Logout(View): def post(self, request): redis = django_redis.get_redis_connection() redis.delete(const.SESSION + request.token) return NbResponse()