三方登陆流程:
微博开放平台设置app和key
请求用户授权Token: https://open.weibo.com/wiki/Oauth2/authorize
获取授权过的Access Token, UID: https://open.weibo.com/wiki/Oauth2/access_token
代码实现:
vue页面代码:
<template> <div> <p><input type="button" value="微博登陆" @click="weibo_login()"></p> <P><a v-if="a==2" :href="weibo_url" class="weibo_login">微博登陆</a></P> </div> </template> <script> import axios from 'axios' export default { name:"weibo", data(){ return{ a:1, weibo_url:'' } }, methods: { weibo_login(){ axios({ url:"http://127.0.0.1:8000/wb/weibourl/", method:"get" }).then(res=>{ this.a = 2 this.weibo_url = res.data.weibo_url }) } }, } </script>
<template> <div> <h1>页面跳转中。。。</h1> </div> </template> <script> import axios from 'axios' export default { name:'weibo_callback', data(){ return{ } }, methods:{ get_code(){ var code = this.$route.query.code console.log(code) axios({ url:"http://127.0.0.1:8000/wb/call_back/?code="+code, method:"get" }).then(res=>{ console.log(res.data) if(res.data.code==200){ sessionStorage.setItem("jwt_token",res.data.token) window.location.href="www.baidu.com" }else if(res.data.code==404){ sessionStorage.setItem("u_id",res.data.uid) this.$router.push({path:"/binduser"}) }else{ alert("授权失败") } }) } }, mounted(){ this.get_code() } } </script>
<template> <div> <p>用户名:<input type="text" v-model="username"></p> <p>密码:<input type="password" v-model="password"></p> <p>手机号:<input type="text" v-model="phone"></p> <p><input type="button" @click="send_bind_info()"></p> </div> </template> <script> document.title = "绑定页面"; import axios from "axios"; export default { // axios-> access_token data: function() { return { password: "", username: "", phone:"" }; }, methods: { send_bind_info: function() { let post_data = new FormData(); let u_id = sessionStorage.getItem("u_id"); post_data.append("password", this.password); post_data.append("username", this.username); post_data.append("phone", this.phone); post_data.append("u_id", u_id); axios({ url: "http://127.0.0.1:8000/wb/bind_user/", method: "post", data: post_data }).then(res => { console.log(res.data) }); } } }; </script>
django代码
import os # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = 'fivz67l6ttp5jlg%$jnrinq=j72re)x-54k(q-%y^l5+(7^h6i' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True ALLOWED_HOSTS = [] # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'appqiniu', 'rest_framework', 'corsheaders', 'rest_framework.authtoken', 'users', 'weiboapp', "redisapp" ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'corsheaders.middleware.CorsMiddleware', ] ROOT_URLCONF = 'django_online.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')] , 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'django_online.wsgi.application' # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': '127.0.0.1', # 数据库主机 'PORT': 3306, # 数据库端口 'USER': 'root', # 数据库用户名 'PASSWORD': '123456', # 数据库用户密码 'NAME': 'drf1908a_ol' # 数据库名字 } } # Password validation # https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', }, { 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', }, { 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', }, ] # Internationalization # https://docs.djangoproject.com/en/2.2/topics/i18n/ LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ STATIC_URL = '/static/' CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_WHITELIST = () CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', 'Pragma', ) SESSION_ENGINE='django.contrib.sessions.backends.cache' REST_FRAMEWORK = { # 身份认证 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', ), #全局配置接口权限 # 'DEFAULT_PERMISSION_CLASSES': ( # 'rest_framework.permissions.IsAuthenticated', # ), } import datetime JWT_AUTH = { 'JWT_AUTH_HEADER_PREFIX': 'JWT', 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1), 'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.views.jwt_response_payload_handler', # 重新login登录返回函数 } AUTH_USER_MODEL='users.User' # 指定使用users APP中的 model的User表作为系统认证时使用表 WEIBO_APP_KEY = '505677658' WEIBO_APP_SECRET = '5689ef360f8e25c1df8a54e8e5653cd2' WEIBO_CALL_BACK = 'http://127.0.0.1:8080/#/weibo_callback/' # 回调路由
#! /usr/bin/env python # -*- coding: utf-8 -*- from django.urls import path,re_path,include from weiboapp import views from rest_framework_jwt.views import obtain_jwt_token # 验证密码后返回token urlpatterns = [ path('weibourl/', views.WBUrl.as_view(), ), path('call_back/', views.WBCallBack.as_view(), ), path('bind_user/', views.BindUser.as_view(), ), ]
from rest_framework_jwt.settings import api_settings from rest_framework import serializers from users.models import User class UserSerializer(serializers.Serializer): id =serializers.IntegerField(read_only=True) username = serializers.CharField() password = serializers.CharField() phone = serializers.CharField() token = serializers.CharField(read_only=True) def create(self, data): user = User.objects.create(**data) #数据库里密码的加密(固定的步骤) user.set_password(data.get('password')) user.save() # 补充生成记录登录状态的token 固定的格式,用过来生成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) #把token发放在user里返回 user.token = token return user def update(self, instance, validated_data): pass
from django.db import models from django.contrib.auth.models import AbstractUser # Create your models here. class User(AbstractUser): username = models.CharField(max_length=64, unique=True) password = models.CharField(max_length=255) phone = models.CharField(max_length=64) pic = models.CharField(max_length=512) token = models.CharField(max_length=255) class WbUser(models.Model): user_app=( (1,"微信"), (2,"微博"), (3,"qq"), (4,"支付宝") ) uid= models.CharField(max_length=128,unique=True) users = models.ForeignKey(User,on_delete=models.SET_NULL,null=True) name = models.CharField(max_length=32,null=True) user_from = models.IntegerField(choices=user_app)
from django.shortcuts import render from rest_framework.response import Response from rest_framework.views import APIView from urllib.parse import urlencode from django_online import settings from rest_framework.permissions import IsAuthenticated,AllowAny import requests from .models import WbUser from rest_framework_jwt.settings import api_settings from .serializers import UserSerializer from django.db import transaction # Create your views here. class WBUrl(APIView): permission_classes = [AllowAny] def get(self,request): url="https://api.weibo.com/oauth2/authorize?" data={ "client_id":settings.WEIBO_APP_KEY, "response_type":"code", 'redirect_uri': settings.WEIBO_CALL_BACK } weibo_url = url+urlencode(data) print(weibo_url) return Response({"weibo_url":weibo_url}) class WBCallBack(APIView): def get(self,request): code = request.query_params.get("code") print(code) data = { 'client_id': settings.WEIBO_APP_KEY, 'client_secret': settings.WEIBO_APP_SECRET, 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': settings.WEIBO_CALL_BACK, } url = 'https://api.weibo.com/oauth2/access_token' response = requests.post(url=url,data=data).json() print(response) uid = response.get('uid') print(uid) if not uid: # 获取不到则为微博code错误 return Response({'code': 201, 'error': '三方授权失败'}) else: try: user = WbUser.objects.get(uid=uid) except Exception as e: return Response({"code":404,"msg":"first time login","uid":uid}) else: jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER payload = jwt_payload_handler(user) # user指的是你查询出来的用户 token = jwt_encode_handler(payload) data={ "code": 200, "token": token, "msg": "login sucess", "username":user.users.username, "user_id":user.users.id } return Response(data,status=200) #检查参数是否齐全 def check_params(list,data): for i in list: if i in data: pass else: return i return False class BindUser(APIView): def post(self,request): params = request.data check_result = check_params(["username","password","phone","u_id"],params) if check_result: data={ "code":200, "msg": "%s is lost" % check_result } return Response(data,status=200) try: ser = UserSerializer(data=params) # print(ser) if ser.is_valid(): #使用事务来处理 with transaction.atomic(): #创建还原点 save_id = transaction.savepoint() try: user = ser.save() wb_res = WbUser.objects.create(uid=params["u_id"],user_from=2,users=user) # transaction.savepoint_commit(save_id) except Exception as e: #返回还原点再次执行 transaction.savepoint_rollback(save_id) finally: #执行成功,提交到数据库 transaction.savepoint_commit(save_id) res_data = ser.data res_data["code"]=200 return Response(res_data, status=200) else: return Response({"code":500,"msg":"failed"},status=200) except Exception as e: # raise e return Response({"code": 5001, "msg": "failed"},status=200)