luffy项目之多方式登录

复习

# git 参考:https://www.cnblogs.com/liuqingzheng/p/15328319.html
# https://www.cnblogs.com/liuqingzheng/p/15325288.html
# https://github.com/VKSRC/Github-Monitor.git
# 1 远程仓库--->git是分布式管理--》本地就可以管理代码--》github,gitee,gitlab

# 2 git remote add origin https:/ssh地址
# 3 git push origin master 
# 4 git branch -a
# 5 项目创建者和开发者
	-远程仓库创建---》把代码提交上去
    -git clone 地址   基于这个继续开发
    
# 6 ssh链接:免密登录和提交代码
	-生成公钥私钥----》公钥给别人(gitee上)
    -remote要变成ssh
    
# 7 协同开发
	-多人操作同一个仓库
    -冲突
# 8 冲突
	-多人开发同一个分支
    -分支合并
# 9 线上分支合并
	-提交pr---》

今日内容

1 Pycharm操作git

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

luffy项目之多方式登录

2 为开源项目贡献代码

# fork代码--->在你仓库就会有这个开源项目---》拉倒你本地,写代码---》提交到你的仓库---》提交pr--》作者同意--》你就合进去了

3 登录注册,前端页面

#  接口分析(5个接口)---》除了验证码,都是操作User表
需要写这五个接口
	-用户名(手机号,邮箱)密码登录接口(多方式登录)
    -手机号+验证码登录
    -发送验证码接口
    -根据手机号判断用户是否注册接口
    -手机号+验证码注册接口
    
    
# 

3.1 前端页面编写 模态框的显示与不显示 Login.vue

<template>
     <div class="login">

        <span @click="close_login">X</span>

    </div>
</template>

<script>
    export default {
        name: "Login",
        methods:{
            close_login(){
                // 控制父组件中的is_login变量编程false
                this.$emit('close_login')
            }
        }
    }
</script>

<style scoped>
  .login {
        width: 100vw;
        height: 100vh;
        position: fixed;
        top: 0;
        left: 0;
        z-index: 10;
        background-color: rgba(0, 0, 0, 0.3);
    }
</style>

3.2 Header.vue

<template>
    <div class="header">
        <div class="slogan">
            <p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p>
        </div>
        <div class="nav">
            <ul class="left-part">
                <li class="logo">
                    <router-link to="/">
                        <img src="../assets/img/head-logo.svg" alt="">
                    </router-link>
                </li>
                <li class="ele">
                    <span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span>
                </li>
                <li class="ele">
                    <span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span>
                </li>
                <li class="ele">
                    <span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span>
                </li>
            </ul>

            <div class="right-part">
                <div>
                    <span @click="go_login">登录</span>
                    <span class="line">|</span>
                    <span>注册</span>
                    <Login v-if="is_login" @close_login="close_login"></Login>
                    <Register v-if="is_register"></Register>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
    import Login from "./Login";
    import Register from "./Register";
    export default {
        name: "Header",
        data() {
            return {
                url_path: sessionStorage.url_path || '/',
                is_login:false,
                is_register:false,
            }
        },
        methods: {
            goPage(url_path) {
                // 已经是当前路由就没有必要重新跳转
                if (this.url_path !== url_path) {
                    this.$router.push(url_path);
                }
                sessionStorage.url_path = url_path;
            },
            go_login(){
                // alert('asfasd')
                this.is_login=true
            },
            close_login(){
                this.is_login=false
            }
        },
        created() {
            sessionStorage.url_path = this.$route.path;
            this.url_path = this.$route.path;
        },
        components:{
            Login,Register
        }
    }
</script>

<style scoped>

    .header {
        background-color: white;
        box-shadow: 0 0 5px 0 #aaa;
    }

    .header:after {
        content: "";
        display: block;
        clear: both;
    }

    .slogan {
        background-color: #eee;
        height: 40px;
    }

    .slogan p {
        width: 1200px;
        margin: 0 auto;
        color: #aaa;
        font-size: 13px;
        line-height: 40px;
    }

    .nav {
        background-color: white;
        user-select: none;
        width: 1200px;
        margin: 0 auto;

    }

    .nav ul {
        padding: 15px 0;
        float: left;
    }

    .nav ul:after {
        clear: both;
        content: '';
        display: block;
    }

    .nav ul li {
        float: left;
    }

    .logo {
        margin-right: 20px;
    }

    .ele {
        margin: 0 20px;
    }

    .ele span {
        display: block;
        font: 15px/36px '微软雅黑';
        border-bottom: 2px solid transparent;
        cursor: pointer;
    }

    .ele span:hover {
        border-bottom-color: orange;
    }

    .ele span.active {
        color: orange;
        border-bottom-color: orange;
    }

    .right-part {
        float: right;
    }

    .right-part .line {
        margin: 0 10px;
    }

    .right-part span {
        line-height: 68px;
        cursor: pointer;
    }

</style>

4 多方式登录接口

# {username:lqz/1234455/3@qq.com,password:1234}--->传到后端(post)-->根据传入的校验用户名和密码---》签发token,用户名,头像

4.1 views.py

class LoginView(GenericViewSet):
    queryset = User.objects.all()
    serializer_class = LoginSerializer

    @action(methods=['POST'], detail=False, )  # user/login/mul_login
    def mul_login(self, request):
        try:
            # 校验规则和签发token都写到序列化类中
            ser = self.get_serializer(data=request.data,context={'request':request})
            ser.is_valid(raise_exception=True)  # 走序列化类的字段自己的规则,局部钩子和全局钩子
            token = ser.context.get('token')
            username = ser.context.get('username')
            icon = ser.context.get('icon')
        except Exception as e:
            raise APIException(str(e))
        return APIResponse(token=token, username=username, icon=icon)

4.2 serializer.py

from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

from rest_framework_jwt.views import obtain_jwt_token
class LoginSerializer(serializers.ModelSerializer):
    # 如果不重写username,username字段自己的校验规则就过不了
    # 如果不重写,字段自己的校验规则(从User表身上映射过来的),最长和最短,由于username是 unique的
    username=serializers.CharField()  # 字段自己的校验规则就没了

    class Meta:
        model = User
        # 往里走--->反序列化校验:username和password---》只是校验长短
        # 往外走--->序列化---》username,icon
        fields = ['username', 'password', 'icon']
        extra_kwargs = {
            'password': {'write_only': True},
            'icon': {'read_only': True}
        }

    def validate(self, attrs):  # 全局钩子
        # 校验用户名和密码是否正确,如果正确,签发token,如果不正确,抛异常
        # 1 获取登录用户
        user = self._get_user(attrs)
        # 2 签发token--django-jwt

        token=self._get_token(user)

        # 3 把token 放入到当前对象中给view用
        self.context['token']=token
        self.context['username']=user.username
        # self.context['icon']=user.icon # icon的有点问题
        # 这个地址是服务端地址,服务端地址从request对象中可以取出request.META['HTTP_HOST']
        request=self.context.get('request')
        self.context['icon']='http://%s/media/'%request.META['HTTP_HOST']+str(user.icon)
        return attrs

    def _get_user(self, attrs):  # 公司里这么写,表示只在类内部用
        # 取出用户的用户名和密码,校验
        username = attrs.get('username')  # 可能是手机号,邮箱和用户名
        password = attrs.get('password')
        # 正则匹配
        if re.match(r'^1[3-9][0-9]{9}$', username):  # 手机号
            user = User.objects.filter(mobile=username).first()
        elif re.match(r'^.+@.+$', username):  # 邮箱
            user = User.objects.filter(email=username).first()
        else:
            user = User.objects.filter(username=username).first()

        if user and user.check_password(password):
            # 校验密码
            return user
        else:
            raise ValidationError('用户名或密码错误')


    def _get_token(self,user):
        # 根据user获取payload
        payload = jwt_payload_handler(user)
        # 根据payload得到token
        token=jwt_encode_handler(payload);
        return token

5 手机号是否存在接口

# 前端取出手机号---》传到后端(post)---》去数据库查询手机号是否存在---》返回是否存的json串
# 按照这种模板写
    try:
		pass
    except Exception as e:
            raise APIException('该手机号不存在')
    return APIResponse(is_exisit=True)#{code:100,msg:成功,is_exisit:true}

5.1 views.py

class UserView(ViewSet):

    # /user/check_mobile---->post请求
    @action(methods=['POST'], detail=False, )
    def check_mobile(self, request):
        mobile = request.data.get('mobile')
        # res=User.objects.filter(mobile=mobile).first()

        try:
            User.objects.get(mobile=mobile)  # 有且只有一个才行,否则报错
            # 一堆逻辑
        except Exception as e:
            # return APIResponse(is_exisit=False)# {code:100,msg:'成功',is_exisit=false}
            raise APIException('该手机号不存在')  # {code:888,msg:'手机号不存在'}

        return APIResponse(is_exisit=True)  # {code:100,msg:成功,is_exisit:true}

6 发送验证码接口准备

# 手机短信发送----》第三方短信平台(阿里大于短信,腾讯云短信)
# 腾讯云短信平台:https://console.cloud.tencent.com/smsv2/guide
# 快速入门
    创建短信签名
    	-申请一个公众号---》个人公众号
    创建短信正文模板
    	-审核
    等待审核
    发送短信
    
    
#	API和SDK的区别
	API:就是一个格接口   http:/asdfasdf/ 
     麻烦,需要分析接口的请求参数和返回参数---》但是通用,有的厂商不提供sdk,只能用API接口
    
    SDK:集成开发工具包,跟语言有关系,有的厂商不提供python的sdk
	

luffy项目之多方式登录

上一篇:Leetcode 24. 两两交换链表中的节点 Swap Nodes in Pairs - Python


下一篇:PyQt5布局管理