绑定用户身份接口
如果用户是首次使用QQ登录,则需要绑定用户,页面如下:
业务逻辑:
- 用户需要填写手机号、密码、图片验证码、短信验证码
- 如果用户未在美多商城注册过,则会将手机号作为用户名为用户创建一个美多账户,并绑定用户
- 如果用户已在美多商城注册过,则检验密码后直接绑定用户
绑定QQ身份的处理流程
后端接口设计
请求方式: POST /oauth/qq/user/
请求参数: JSON 或 表单
参数 | 类型 | 是否必须 | 说明 |
---|---|---|---|
mobile | str | 是 | 手机号 |
password | str | 是 | 密码 |
sms_code | str | 是 | 短信验证码 |
access_token | str | 是 | 凭据 (包含openid) |
返回数据: JSON
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
token | str | 是 | JWT token |
id | int | 是 | 用户id |
username | str | 是 | 用户名 |
在OAuthQQ辅助类中增加
@classmethod
def check_save_user_token(cls, token, secret_key=None, expires=None):
"""
对token进行校验:
token: 对openid加密之后生成的token
secret_key: 密钥
expires: token有效时间
"""
if secret_key is None:
secret_key = cls.SECRET_KEY
if expires is None:
expires = cls.EXPIRES_IN
serializer = TJWSSerializer(secret_key, expires)
try:
data = serializer.loads(token)
except BadData:
return None
else:
return data.get('openid')
新建oauth/serializers.py文件,
class OAuthQQUserSerializer(serializers.ModelSerializer):
"""
保存QQ用户序列化器
"""
sms_code = serializers.CharField(label='短信验证码', write_only=True)
access_token = serializers.CharField(label='操作凭证', write_only=True)
token = serializers.CharField(read_only=True)
mobile = serializers.RegexField(label='手机号', regex=r'^1[3-9]\d{9}$')
class Meta:
model = User
fields = ('mobile', 'password', 'sms_code', 'access_token', 'id', 'username', 'token')
extra_kwargs = {
'username': {
'read_only': True
},
'password': {
'write_only': True,
'min_length': 8,
'max_length': 20,
'error_messages': {
'min_length': '仅允许8-20个字符的密码',
'max_length': '仅允许8-20个字符的密码',
}
}
}
def validate(self, attrs):
# 检验access_token
access_token = attrs['access_token']
openid = OAuthQQ.check_save_user_token(access_token)
if not openid:
raise serializers.ValidationError('无效的access_token')
attrs['openid'] = openid
# 检验短信验证码
mobile = attrs['mobile']
sms_code = attrs['sms_code']
redis_conn = get_redis_connection('verify_codes')
real_sms_code = redis_conn.get('sms_%s' % mobile)
if real_sms_code.decode() != sms_code:
raise serializers.ValidationError('短信验证码错误')
# 如果用户存在,检查用户密码
try:
user = User.objects.get(mobile=mobile)
except User.DoesNotExist:
pass
else:
password = attrs['password']
if not user.check_password(password):
raise serializers.ValidationError('密码错误')
attrs['user'] = user
return attrs
def create(self, validated_data):
openid = validated_data['openid']
user = validated_data.get('user')
mobile = validated_data['mobile']
password = validated_data['password']
if not user:
# 如果用户不存在,创建用户,绑定openid(创建了OAuthQQUser数据)
user = User.objects.create_user(username=mobile, mobile=mobile, password=password)
OAuthQQUser.objects.create(user=user, openid=openid)
# 签发jwt token
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
user.token = token
return user
在oauth/views.py修改QQAuthUserView 视图
class QQAuthUserView(CreateAPIView):
"""
QQ登录的用户
"""
serializer_class = OAuthQQUserSerializer
def get(self, request):
...
前端
在oauth_back.js中实现
// 保存
on_submit: function(){
this.check_pwd();
this.check_phone();
this.check_sms_code();
if(this.error_password == false && this.error_phone == false && this.error_sms_code == false) {
axios.post(this.host + '/oauth/qq/user/', {
password: this.password,
mobile: this.mobile,
sms_code: this.sms_code,
access_token: this.access_token
}, {
responseType: 'json',
})
.then(response => {
// 记录用户登录状态
sessionStorage.clear();
localStorage.clear();
localStorage.token = response.data.token;
localStorage.user_id = response.data.id;
localStorage.username = response.data.username;
location.href = this.get_query_string('state');
})
.catch(error=> {
if (error.response.status == 400) {
this.error_sms_code_message = error.response.data.message;
this.error_sms_code = true;
} else {
console.log(error.response.data);
}
})
}
}