• web 部署专题(九):Nginx 前后端分离中csrf_token 认证的实现


    1. 思路

    参考:https://stackoverflow.com/questions/20826201/simple-csrf-protection-using-nginx-alone?r=SearchResults

    第一步:

           前端页面向后端发送生成csrf请求(get 方法),后端服务器生成csrf_token返回gei前端

    第二步:

          前端收到csrf_token后,将csrf_token写入cookie中,在post请求中,随cookie与请求头发送到后端中。

    2.相关代码

    2.1 Nginx 配置

    ##
    # You should look at the following URL's in order to grasp a solid understanding
    # of Nginx configuration files in order to fully unleash the power of Nginx.
    # https://www.nginx.com/resources/wiki/start/
    # https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
    # https://wiki.debian.org/Nginx/DirectoryStructure
    #
    # In most cases, administrators will remove this file from sites-enabled/ and
    # leave it as reference inside of sites-available where it will continue to be
    # updated by the nginx packaging team.
    #
    # This file will automatically load configuration files provided by other
    # applications, such as Drupal or Wordpress. These applications will be made
    # available underneath a path with that package name, such as /drupal8.
    #
    # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
    ##
    
    # Default server configuration
    #
    #server {
    #    listen 80 default_server;
    #    listen [::]:80 default_server;
    
        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;
    
    #    root /var/www/html;
    
        # Add index.php to the list if you are using PHP
    #    index index.html index.htm index.nginx-debian.html;
    
    #    server_name _;
    
    #    location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to displaying a 404.
    #        try_files $uri $uri/ =404;
    #    }
    
        # pass PHP scripts to FastCGI server
        #
        #location ~ .php$ {
        #    include snippets/fastcgi-php.conf;
        #
        #    # With php-fpm (or other unix sockets):
        #    fastcgi_pass unix:/run/php/php7.3-fpm.sock;
        #    # With php-cgi (or other tcp sockets):
        #    fastcgi_pass 127.0.0.1:9000;
        #}
    
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /.ht {
        #    deny all;
        #}
    #}
    
    
    # Virtual Host configuration for example.com
    #
    # You can move that to a different file under sites-available/ and symlink that
    # to sites-enabled/ to enable it.
    #
    server {
        listen 80;
        listen [::]:80;
    #
        server_name localhost;
    #
        #root /var/www/example.com;
    #    root /var/www/html;
    
    #    root /home/pi/Desktop/tornado_example/linux_tornado/movie/static;
    #    index index.html;
    #
        location ~* /admin/ {
    #        try_files $uri $uri/ =404;
                    proxy_pass http://127.0.0.1:5000;
    #                proxy_connect_timeout 600;
    #                proxy_read_timeout 600;
                    proxy_cookie_domain localhost:5000 localhost:80;   #保证cookie不受跨域影响    
        }
    
    
        location / {
                 root /var/www/;
                 index index.nginx-debian.html;
    
        }
    
        location /html/ {
                 root /var/www/static/;
                 index index.nginx-debian.html;
    
        }
    }

    2.1 flask 后端编写

    from flask_wtf import csrf
    
    @admin.route("/csrf_token")
    def get_csrf_token():
        "生成csrf_token"
        csrf_token = csrf.generate_csrf()
        return '{"errno":0,"errmsg":"OK","csrf_token":"%s"}' % csrf_token,200,{"Content-Type":"application/json"} 

    2.2 前端编写

    js 文件

    login.js

    function getCookie(name) {
        var r = document.cookie.match("\b" + name + "=([^;]*)\b");
        return r ? r[1] : undefined;
    }
    
    function setCookie() {
    
        $.get("/admin/csrf_token",function(resp) {  // 向后端发送获取csrf_token 请求
         
          $("#csrf_token").attr("csrf_token",resp.csrf_token) // 将得到的 csrf_token写道html元素中
        });
    
    }
    
    
    
    
    $(document).ready(function() {
        $("#user").focus(function(){
            $("#user-err").hide();
        });
        $("#password").focus(function(){
            $("#password-err").hide();
        });
    
    
       setCookie() //获取csrf_token
    
    
    
        $(".form-login").submit(function(e){
            e.preventDefault();
            account = $("#user").val();
            passwd = $("#password").val();
            if (!account) {
                $("#user-err span").html("请填写正确帐号!");
                $("#user-err").show();
                return;
            } 
            if (!passwd) {
                $("#password-err span").html("请填写密码!");
                $("#password-err").show();
                return;
            }
            var data = {
                account:account,
                password:passwd
            };
    
    
            var csrf_data = $("#csrf_token").attr("csrf_token");  // 从html 获取csrf_token
    
            document.cookie = "csrf_token" + "=" + csrf_data;  // 将csrf_token 写入cookie
    
    
    
    
            var jsonData = JSON.stringify(data);
            $.ajax({  // post 请求登录
                url:"/admin/sessions", 
                type:"post",
                data:jsonData,
                contentType:"application/json",
                dataType:"json",
                headers:{
                    "X-CSRFToken":getCookie("csrf_token")
                },
                success:function (data) {
                    if (data.errno=="0"){
                        // 登录成功,跳转到主页
                        location.href ="/html/index.html"
                    } else {
                      // 其他错误信息,在页面中展示
                      $("#password-err span").html(data.errmsg);
                      $("#password-err").show();
                    }
                }
            });
        });
    })

    html 文件

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>招投标爬虫管理</title>
        <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
    
        <link rel="stylesheet" href="../static/admin/bootstrap/css/bootstrap.min.css">
        <link rel="stylesheet" href="../static/fonts/css/font-awesome.min.css">
        <link rel="stylesheet" href="../static/ionicons/css/ionicons.min.css">
        <link rel="stylesheet" href="../static/admin/dist/css/AdminLTE.min.css">
        <link rel="stylesheet" href="../static/admin/plugins/iCheck/square/blue.css">
    </head>
    <body class="hold-transition login-page">
    <div class="login-box">
        <div class="login-logo">
            <a href=""><b>招投标爬虫系统</b></a>
        </div>
        <div class="login-box-body">
            <p class="login-box-msg"></p>
            <form class="form-login">
                <div class="form-group has-feedback">
                    <input name="user" id="user" type="text" class="form-control" placeholder="请输入账号!">
                    <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
                    <div class="col-md-12" id="input_user"></div>
                </div>
                <div class="error-msg" id="user-err"><i class="fa fa-exclamation-circle"></i><span></span></div>
                <div class="form-group has-feedback">
                    <input name="pwd" id="password" type="password" class="form-control" placeholder="请输入密码!">
                    <span class="glyphicon glyphicon-lock form-control-feedback"></span>
                    <div class="col-md-12" id="input_pwd"></div>
                </div>
           <div class="error-msg" id="password-err"><i class="fa fa-exclamation-circle"></i><span></span></div>
                <div class="form-group has-feedback">
                    <input name="csrf_token" id="csrf_token" type="hidden" class="form-control" >
                </div>
    
               <div class="row">
                    <div class="col-xs-8"></div>
                    <div class="col-xs-4">
                <input id="btn-sub" type="submit" class="btn btn-primary btn-block btn-flat" value="登录">
                    </div>
                </div>
            </form>
        </div>
    </div>
    <script src="../static/admin/plugins/jQuery/jQuery-2.2.0.min.js"></script>
    <script src="../static/admin/bootstrap/js/bootstrap.min.js"></script>
    <script src="../static/admin/plugins/iCheck/icheck.min.js"></script>
    
    <script src="/static/js/crawler/login.js"></script>
    
    
    </body>
    </html>
  • 相关阅读:
    C# 隐式转换 显示转换
    C# 枚举几种写法细节
    C# System.Int32 与 int 区别
    JavaScript中的闭包
    JS Arguments对象
    分页存储过程 sql
    JS Select 选项清空
    WebGL学习笔记三
    WebGL学习笔记二
    WebGL学习笔记一
  • 原文地址:https://www.cnblogs.com/qiu-hua/p/12773381.html
Copyright © 2020-2023  润新知