python开发基础篇2——登陆机制

一、管理平台页面布局

应用名称:

  1. dashboard:存放公共

  2. k8s:

    • Node:K8s集群计算节点。
    • Namespaces:命名空间,用于隔离资源。
    • PersistentVolumes(PV):持久卷,存储数据
  3. workload:

    • Deployments:无状态应用部署控制器。
    • DaemonSets:守护进程控制器,在每个节点启动一个Pod。
    • StatefulSets:有状态应用部署控制器。
    • Pods:K8s最小部署单元
  4. loadbalancer:

    • Services:为Pod提供服务发现和负载均衡。
    • Ingresses:集群中应用统一入口,对外暴露应用
  5. storage:

    • PersistentVolumeClaims(PVC):持久卷申请,与PV绑定。
    • ConfigMaps:存储配置内容,例如应用程序配置文件。
    • Secrets:存储应用敏感数据,例如用户名密码

二、登录页面

登录认证流程:

  • AJAX提交登录认证数据 到服务端——> 验证提交数据格式合法性(编写一个登录认证检查函数)——> 确认没问题向session里写入认证信息 ——> 返回AJAX,AJAX跳转到首页。
    在这里插入图片描述

2.1 token登录

  • 验证token登录验证逻辑。若输入的token是正确有效的,则会将token写入到数据库中的session保存,方便下次登录。

1.根据布局创建对象的django 应用。

python manage.py startapp dashboard
python manage.py startapp k8s
python manage.py startapp workload
python manage.py startapp loadbalancer
python manage.py startapp storage  

2.启用django默认数据库,用于保存session状态。

python manage.py makemigrations
python manage.py migrate

在这里插入图片描述

3.验证代码。

##########################################################
##自定义模块。
from kubernetes import client,config
import os

#连接k8s验证输入的token或者kubeconfig是否有效。
def auth_check(auth_type,token):
    if auth_type == "token":
        configuration = client.Configuration()
        configuration.host = "https://192.168.161.120:6443"  # APISERVER地址
        # ca_file = os.path.join(os.getcwd(), "ca.crt") # K8s集群CA证书(/etc/kubernetes/pki/ca.crt)
        # configuration.ssl_ca_cert= ca_file
        configuration.verify_ssl = False
        configuration.api_key = {"authorization": "Bearer " + token}   ##固定格式。
        client.Configuration.set_default(configuration)
        apps_api = client.AppsV1Api()
        try:
            core_api = client.CoreApi()
            core_api.get_api_versions()  # 查看8s版本,由此验证是否有效的
            return True
        except Exception as e:
            print(e)
            return False
    elif auth_type == "kubeconfig":
        pass
##########################################################
##视图逻辑。
from django.shortcuts import render
from Layui import k8s  ##导入自定义模块。
from django.http import  JsonResponse

def index(request):
    return render(request,'index.html')

def login(request):
    if request.method == "GET":
        return render(request,'login.html')
    elif request.method == "POST":
        token =request.POST.get("token")
        #处理token登录。
        if token:
            if k8s.auth_check("token",token):  # 如token是有效登录成功
                request.session['is login'] = True
                request.session['auth_type'] = token  # 用于后期前端调用django,django拿这个信息去请k8s api
                request.session['token'] = token
                code = 0
                msg = "登录成功"
            else:
                code = 1
                msg = "Token无效!"
        else:
        #处理kubeconfig文件登录。
            file_obj  = request.FILES.get("file")
        result = {'code': code,'msg': msg}
        return JsonResponse(result)
##########################################################
##子模板文件。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <style>
        /* 整个内容区 */
        body {
            background-color: #edeff0;
        }
        .a {
            width: 900px;
            height: 400px;
            background-color: white;
            /* 定位到中间 */
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            margin: auto;
            /* 添加阴影 */
            box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
        }
        /* 头部蓝色背景 */
        .c {
            height: 60px;
            width: 900px;
            background-color: #326de6;
            color: white;
            font-size: 20px;
        }
        /* 头部蓝色中文字向右移动并居中*/
        .c p {
            padding-left: 300px;
            padding-top: 12px;
            font-weight: bold;
            font-size: 26px;
            letter-spacing: 1px;
        }
        /* 所有文字右、下移 */
        .d,.e,.f,.g {
            padding-left: 300px;
        }

        /* 给选择按钮加超链接并加粗 */
        .d a, .e a {
            font-weight: bold;
            font-size: 18px;
            text-decoration: none;
        }
        /* 超链接显示处理 */
        a:active, a:link, a:visited, a:hover {color: black}
        /* 文字左、右向内靠拢 */
        .p {
            padding-left: 10px;
            padding-right: 10px;
        }
        /* 实心圆外面圆 */
        .s {
            display: block;
            width: 18px;
            height: 18px;
            border-radius: 20px;
            border: 2px solid gray;
            float: left;  /* 与Token水平 */
            margin-right: 10px;
        }
        /* 实心圆 */
        .ss {
            display: block;
            width: 10px;
            height: 10px;
            background-color: #326de6;
            border-radius: 20px;
            border: 2px solid white;
            /* 上、左移动,让实心圆居中 */
            position: relative;
            top: 13%;
            left: 10%;
        }
        .f, .g {
            display: none;  /* 默认两个input隐藏 */
        }
        .f input {
            width: 500px;
            height: 25px;
            border-style: none;
            border-bottom: 1px solid black;
            outline: none;  /* 点击输入框不显示外边框 */
            margin-top: 10px;
            margin-left: 10px;
        }
        .g input {
            margin-top: 10px;
            margin-left: 10px;
            color: gray;
            outline: none;
        }
        #btn {
            height: 50px;
            width: 150px;
            margin-left: 400px;
            margin-top: 40px;
            border-style: none;
            font-size: 22px;
            background-color: #326de6;
            color: white;
            padding: 8px 15px 8px 15px;
            outline: none;
            box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
        }
        #btn:hover {
            cursor: pointer;
        }

    </style>
</head>
<body>
{% csrf_token %}
<div class="a">
    <div class="b">
        <div class="c">
            <p>欢迎访问Kubernetes管理平台</p>
        </div>
        <div>
            <div class="d">
                <p><a href="#" id="tokenBtn"><span class="s" id="s1"><span id="ss1"></span></span>Token</a></p>
                <p class="p"></p>
            </div>
            <div class="e">
                <p><a href="#" id="kubeBtn"><span class="s" id="s2"><span id="ss2"></span></span>Kubeconfig</a></p>
                <p class="p"></p>
            </div>
            <div class="f" id="token">
                <input type="password" name="token" placeholder="输入token" >
            </div>
            <div class="g" id="kube">
                <input type="file" name="kubeconfig" id="kubeconfig">
            </div>
            <p><button type="button" id="btn">登录</button>&nbsp;&nbsp;&nbsp;<span id="notice"></span></p>
        </div>

    </div>
</div>
<script type="text/javascript">
    // 默认选中Toekn认证。
    $("#token").css("display", "inline");  // 显示输入token
    $("#s1").css("border", "2px solid #326de6");  // 边框改为蓝色
    $("#ss1").addClass("ss");  // 添加蓝色实心圆

    $("#tokenBtn").click(function () {
        $("#token").css("display", "inline");  // 显示输入token
        $("#kube").css("display", "none");  // 另外一个隐藏

        $("#s1").css("border", "2px solid #326de6");  // 边框改为蓝色
        $("#s2").css("border", "2px solid gray");  // 另外一个,边框改为灰色

        $("#ss1").addClass("ss");  // 添加蓝色实心圆
        $("#ss2").removeClass("ss");  // 去掉蓝色实心圆
    });
    $("#kubeBtn").click(function () {
        $("#kube").css("display", "inline");   // 显示选择文件框
        $("#token").css("display", "none");  // 另外一个隐藏

        $("#s1").css("border", "2px solid gray");  // 另外一个,边框改为蓝灰色
        $("#s2").css("border", "2px solid #326de6");  // 边框改为蓝色

        $("#ss2").addClass("ss");  // 添加蓝色实心圆
        $("#ss1").removeClass("ss");  // 去掉蓝色实心圆
    });
    $("#btn").click(function () {
        var csrf_token = $('[name="csrfmiddlewaretoken"]').val();
        // 判断选择的认证方式,即有实心圆类
        if ($("#ss1").hasClass("ss")) {
            var token = $("input[name='token']").val();
            // 判断输入是否为空
            if (! token) {
                $("#notice").html("请输入Token!").css("color", "red");
                return
            }
            var data = {'token': token, 'csrfmiddlewaretoken': csrf_token};
            $.ajax({
                type: "POST",
                url: "/login/",
                timeout: 5000,
                dataType: "json",
                data: data,
                success: function(res) {
                    if (res.code == 0) {
                        location.href = "/"
                    } else if (res.code == 1){
                        $("#notice").html(res.msg).css("color", "red");
                    }
                },
                error: function (res) {
                    $("#notice").html("服务器接口异常!").css("color", "red");
                }
            })
        } else if ($("#ss2").hasClass("ss")) {
            var fd = new FormData();
            // var file = $("input[name='kubeconfig']")[0].files[0]);
            var file = $("#kubeconfig")[0].files[0];
            if (! file) {
                $("#notice").html("请选择kubeconfig文件!").css("color", "red");
                return
            }
            fd.append('file', file);
            fd.append("csrfmiddlewaretoken", csrf_token);
            $.ajax({
                type: "POST",
                url: "/login/",
                timeout: 5000,
                dataType: "json",
                data: fd,
                processData: false,
                contentType: false,
                success: function(res) {
                    if (res.code == 0) {
                        location.href = "/"
                    } else if (res.code == 1){
                        $("#notice").html(res.msg).css("color", "red");
                    }
                },
                error: function () {
                    $("#notice").html("服务器接口异常!").css("color", "red");
                }
            })
        }
    })
</script>
</body>
</html>
##########################################################
##母版文件。
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <title>{% block title %}{% endblock %}</title>
  <link rel="stylesheet" href="/static/layui/css/layui.css">
</head>
<div style="width: 100px;height: 100px;background-color: oldlace;display: none" id="qingjun">
</div>

<body>
<div class="layui-layout layui-layout-admin">
  <div class="layui-header layui-bg-cyan">
    <div class="layui-logo layui-hide-xs layui-bg-cyan">DevOps管理平台</div>
    <ul class="layui-nav layui-layout-right">
      <li class="layui-nav-item layui-hide layui-show-md-inline-block">
        <a href="/logout">
          <img src="//tva1.sinaimg.cn/crop.0.0.118.118.180/5db11ff4gw1e77d3nqrv8j203b03cweg.jpg" class="layui-nav-img">
          退出
        </a>
        <!--
        <dl class="layui-nav-child">
          <dd><a href="">Your Profile</a></dd>
          <dd><a href="">Settings</a></dd>
          <dd><a href="">Sign out</a></dd>
        </dl>
        -->
      </li>
        <!--
      <li class="layui-nav-item" lay-header-event="menuRight" lay-unselect>
        <a href="javascript:;">
          <i class="layui-icon layui-icon-more-vertical"></i>
        </a>
      </li>
        -->
    </ul>
  </div>

  <div class="layui-side layui-bg-black">
    <div class="layui-side-scroll layui-bg-cyan">
      <!-- 左侧导航区域(可配合layui已有的垂直导航) -->
      <ul class="layui-nav layui-nav-tree layui-bg-cyan" lay-filter="test">
        <li class="layui-nav-item">
          <a class="" href="/"><i class="layui-icon layui-icon-home" style="color: #00FFFF;font-size: 20px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;仪表盘</i></a>
        </li>

        <li class="layui-nav-item {% block item-1 %}{% endblock %}">
          <a class="" href="javascript:;"><i class="layui-icon layui-icon-app" style="color: #01AAED;font-size: 15px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Kubernetes</i></a>
          <dl class="layui-nav-child">
            <dd><a href="{% url 'node' %}" class="{% block item-1-1 %}{% endblock %}">Node</a></dd>
            <dd><a href="{% url 'namespace' %}" class="{% block item-1-2 %}{% endblock %}">NameSpace</a></dd>
          </dl>
        </li>
        <li class="layui-nav-item {% block item-2 %}{% endblock %}">
          <a href="javascript:;"><i class="layui-icon layui-icon-template-1" style="color: #01AAED;font-size: 15px">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Workload</i></a>
          <dl class="layui-nav-child">
            <dd><a href="{% url 'deployment' %}" class="{% block item-2-1 %}{% endblock %}">Deployment</a></dd>
            <dd><a href="{% url 'daemonset' %}" class="{% block item-2-2 %}{% endblock %}">DaemonSet</a></dd>
{#            <dd><a href="">超链接</a></dd>#}
          </dl>
{#        </li>#}
{#        <li class="layui-nav-item"><a href="javascript:;">click menu item</a></li>#}
{#        <li class="layui-nav-item"><a href="">the links</a></li>#}
      </ul>
    </div>
  </div>

  <div class="layui-body" style="background-color: #cccccc">
    <!-- 内容主体区域 -->
    <div style="padding: 15px;">{% block context%}{% endblock %}</div>
  </div>

  <div class="layui-footer" style="text-align: center">
    <!-- 底部固定区域 -->
    k8s管理平台
  </div>
</div>
<script src="/static/layui/layui.js"></script>
{% block custom_js %}{% endblock %}
<script>
//JS
layui.use(['element', 'layer', 'util'], function(){
  var element = layui.element
  ,layer = layui.layer
  ,util = layui.util
  ,$ = layui.$;

  //头部事件
  util.event('lay-header-event', {
    //左侧菜单事件
    menuLeft: function(othis){
      layer.msg('展开左侧菜单的操作', {icon: 0});
    }
    ,menuRight: function(){
      layer.open({
        type: 1
        ,content: '<div style="padding: 15px;">处理右侧面板的操作</div>'
        ,area: ['260px', '100%']
        ,offset: 'rt' //右上角
        ,anim: 5
        ,shadeClose: true
      });
    }
  });

});
</script>
</body>
</html>

4.token验证,查看数据库是否保存了token信息。
在这里插入图片描述
在这里插入图片描述
5.验证数据库中的session保存的返回信息。
在这里插入图片描述

2.2. kubeconfig登录

  • 验证使用正确的kubeconfig文件登录,则会登录到主页。

1.自定义一个类,在数据库中创建一张表,用于保存kubeconfig文件内容。

#######################################################
##生成一张数据库表,用于保存kubeconfig文件内容。dasshboard/models下定义一个类。
from django.db import models
class User(models.Model):
    auth_type = models.CharField(max_length=30)
    token = models.CharField(max_length=100)
    content = models.TextField()
    datetime = models.DateTimeField(auto_now=True)
#######################################################
##同步数据库。settings文件添加如下一行。
INSTALLED_APPS = [
     ......
    'dashboard'
]

python manage.py makemigrations
python manage.py migrate

在这里插入图片描述
2.添加视图。

import requests
from django.shortcuts import render,redirect
from Layui import k8s  ##导入自定义模块。
from django.http import  JsonResponse
from  dashboard.models import User
def login(request):
    if request.method == "GET":
        return render(request,'login.html')
    elif request.method == "POST":
        token =request.POST.get("token")
        #处理token登录。
        if token:
            if k8s.auth_check("token",token):  # 如token是有效登录成功
                request.session['is_login'] = True
                request.session['auth_type'] = 'token'  # 用于后期前端调用django,django拿这个信息去请k8s api
                request.session['token'] = token
                code = 0
                msg = "登录成功"
            else:
                code = 1
                msg = "Token无效!"
        else:
           #处理kubeconfig文件登录。
            file_obj  = request.FILES.get("file")
            import random
            token_random = str(random.random()).split('.')[1]  ##生成一个随机数作为标识。
            try:
                content = file_obj.read().decode()  ##bytes ——> str
                User.objects.create(
                    auth_type="kubeconfig",
                    token=token_random,
                    content=content
                )
                code = 0
                msg = "登陆成功"
            except Exception:
                code = 1
                msg = "kubeconfig文件错误!"
            if k8s.auth_check('kubeconfig',token_random):
                request.session['is_login'] = True
                request.session['auth_type'] = 'kubeconfig'  # 用于后期前端调用django,django拿这个信息去请k8s api
                request.session['token'] = token_random
                code = 0
                msg = "登陆成功"
            else:
                User.objects.get(token=token_random).delete()
                code = 1
                msg = "kubeconfig文件无效!!!"
        result = {'code': code,'msg': msg}
        return JsonResponse(result)

3.修改自定义模块类。

from kubernetes import client,config
import os
from dashboard.models import User
import yaml

# 连接k8s验证输入的token或者kubeconfig是否有效。
def auth_check(auth_type,token=None):
    if auth_type == "token":
        configuration = client.Configuration()
        configuration.host = "https://192.168.161.120:6443"  # APISERVER地址
        # ca_file = os.path.join(os.getcwd(), "ca.crt") # K8s集群CA证书(/etc/kubernetes/pki/ca.crt)
        # configuration.ssl_ca_cert= ca_file
        configuration.verify_ssl = False
        configuration.api_key = {"authorization": "Bearer " + token}   ##固定格式。
        client.Configuration.set_default(configuration)
        apps_api = client.AppsV1Api()
        try:
            core_api = client.CoreApi()
            core_api.get_api_versions()  # 查看8s版本,由此验证是否有效的
            return True
        except Exception as e:
            print(e)
            return False
    elif auth_type == "kubeconfig":
        user = User.objects.get(token=token)
        content = user.content
        yaml_content = yaml.load(content, Loader=yaml.FullLoader) ##yaml文件转为json
        print(yaml_content)
        try:
            config.load_kube_config_from_dict(yaml_content)
            core_api = client.CoreApi()
            core_api.get_api_versions()   # 查看k8s版本,由此验证是否有效的
            return True
        except Exception as e:
            print(e)
            return False

4.使用正确的Kubeconfig文件登陆成功,其他文件登陆失败。
在这里插入图片描述
在这里插入图片描述

2.3 添加装饰器

  • 引用装饰器,使得访问127.0.0.1:8000也是登录页面,而不是首页。

1.在自定义模块文件中添加。

from   django.shortcuts import redirect
def self_login_required(func):
    def inner(request, *args, **kwargs):
        is_login = request.session.get('is_login', True)
        if is_login:
            return func(request, *args, **kwargs)
        else:
            return redirect("/login")
    return inner

2.首页引用装饰器。

@k8s.self_login_required
def index(request):
    return render(request,'index.html')

3.查看效果。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百慕卿君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值