www.businessplus.co.kr/

로그인 페이지
네비바와 리스트페이지
토글형 메뉴 게시판
토글형 상세게시판과 리스트게시판
갤러리형 게시판

 

글쓰기 페이지
상세보기 페이지
수정게시판
배너 페이지 수정 게시판(수정만 가능)
테이블 
공지사항 테이블
미디어/갤러리 테이블
배너 테이블
로그인 테이블

 

vue 리스트 게시판 모습
새로운 사용자를 추가시 모달창을 불러온다.
DB저장 성공시 뜨는 메세지.(오류 메세지로 출력가능)

 

수정시 모달창이 뜨면서 수정 가능
성공시 뜨는 메세지(오류 메세지도 출력가능)
유저 삭제시 뜨는 모달창
성공시 뜨는 메시지(오류도 출력가능)

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>


    <!-- CSS only -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous" />
    <script src="https://kit.fontawesome.com/42e2ecb8e0.js" crossorigin="anonymous"></script>
    <style type="text/css">
        #overlay {
            position: fixed;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.6);
        }
    </style>

</head>

<body>
    <!-- header -->
    <div id="app">
        <div class="container-fluid">
            <div class="row bg-dark">
                <div class="col-lg-12">
                    <p class="text-center text-light display-4 pt-2" style="font-size: 25px">
                        CRUD 어플리케이션 vue, PHP, mysqli
                    </p>
                </div>
            </div>
        </div>
        <div class="container">
            <div class="row mt-3">
                <div class="col-lg-6">
                    <h3 class="text-info">등록 된 유저들</h3>
                </div>
                <div class="col-lg-6">
                    <button class="btn btn-info float-right" @click="showAddModal=true">
              <i class="fas fa-user"></i> &nbsp;  &nbsp; 새롭게 추가
            </button>
                </div>
            </div>
            <hr class="bg-info" />
            <div class="alert alert-danger" v-if="errorMsg">{{ errorMsg }}</div>
            <div class="alert alert-success" v-if="successMsg">{{ successMsg }} </div>

            <!--디스플레이 레코드-->
            <div class="row">
                <div class="col-lg-12">
                    <table class="table table-bordered table-striped">
                        <thead>
                            <tr class="text-center bg-info text-light">
                                <th>ID</th>
                                <th>이름</th>
                                <th>이메일</th>
                                <th>핸드폰</th>
                                <th>수정</th>
                                <th>삭제</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr class="text-center" v-for="user in users">
                                <td>{{ user.id }}</td>
                                <td>{{ user.name }}</td>
                                <td>{{ user.email }}</td>
                                <td>{{ user.phone }}</td>
                                <td>
                                    <a href="#" class="text-success" @click="showEditModal=true; selectUser(user);"><i class="fas fa-edit"></i></a>
                                </td>
                                <td>
                                    <a href="#" class="text-danger" @click="showDeleteModal=true; selectUser(user);"><i class="fas fa-trash-alt"></i></a>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!--새로운 사용자 추가 모달-->
        <div id="overlay" v-if="showAddModal">
            <div class="modal-dialog">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title">새로운 사용자 추가</h5>
                        <button type="button" class="close" @click="showAddModal=false">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body p-4">
                        <form action="#" method="post">
                            <div class="form-group">
                                <input type="text" name="name" class="form-control form-control-lg" placeholder="name" v-model="newUser.name">
                            </div>
                            <div class="form-group">
                                <input type="text" name="email" class="form-control form-control-lg" placeholder="email" v-model="newUser.email">
                            </div>
                            <div class="form-group">
                                <input type="text" name="phone" class="form-control form-control-lg" placeholder="phone" v-model="newUser.phone">
                            </div>
                            <div class="form-group">
                                <button class="btn btn-info btn-block btn-lg" @click="showAddModal=false; addUser(); clearMsg();">사용자 추가</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <!--사용자 수정 모달-->
        <div id="overlay" v-if="showEditModal ">
            <div class="modal-dialog ">
                <div class="modal-content ">
                    <div class="modal-header ">
                        <h5 class="modal-title ">사용자 수정</h5>
                        <button type="button " class="close " @click="showEditModal=false ">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body p-4 ">
                        <form action="# " method="post ">
                            <div class="form-group ">
                                <input type="text " name="name " class="form-control form-control-lg" v-model="currentUser.name">
                            </div>
                            <div class="form-group ">
                                <input type="text " name="email " class="form-control form-control-lg" placeholder="이메일" v-model="currentUser.email">
                            </div>
                            <div class="form-group ">
                                <input type="text " name="phone " class="form-control form-control-lg" placeholder="핸드폰" v-model="currentUser.phone">
                            </div>
                            <div class="form-group ">
                                <button class="btn btn-info btn-block btn-lg " @click="showEditModal=false; updateUser(); clearMsg();">사용자 업데이트</button>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <!--사용자 삭제 모달-->
        <div id="overlay" v-if="showDeleteModal ">
            <div class="modal-dialog ">
                <div class="modal-content ">
                    <div class="modal-header ">
                        <h5 class="modal-title ">사용자 삭제</h5>
                        <button type="button " class="close " @click="showDeleteModal=false ">
                            <span aria-hidden="true ">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body p-4 ">
                        <h4 class="text-danger ">정말 삭제하시겠습니까?</h4>
                        <h5>당신은 '{{ currentUser.name }}'를 삭제합니다.</h5>
                        <hr>
                        <button class="btn btn-danger btn-lg " @click="showDeleteModal=false; deleteUser(); clearMsg(); ">네</button> &nbsp;&nbsp;&nbsp;&nbsp;
                        <button class="btn btn-success btn-lg " @click="showDeleteModal=false ">아니오</button>
                    </div>
                </div>
            </div>
        </div>

    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.20.0/axios.min.js "></script>
    <script src="https://cdn.jsdelivr.net/npm/vue "></script>
    <script>
        var app = new Vue({
            el: "#app ",
            data: {
                errorMsg: "",
                successMsg: "",
                showAddModal: false,
                showEditModal: false,
                showDeleteModal: false,
                users: [],
                newUser: {
                    name: "",
                    email: "",
                    phone: ""
                },
                currentUser: {}
            },

            mounted: function() {
                this.getAllUsers();
            },
            methods: {

                getAllUsers() {
                    axios.get("http://localhost/crud-vue-php/process.php?action=read").then(function(response) {
                        if (response.data.error) {
                            app.errorMsg = response.data.message;
                        } else {
                            app.users = response.data.users;
                        }
                    });
                },

                addUser() {
                    var formData = app.toFormData(app.newUser);
                    axios.post("http://localhost/crud-vue-php/process.php?action=create", formData).then(function(response) {
                        app.newUser = {
                            name: "",
                            email: "",
                            phone: ""
                        };
                        if (response.data.error) {
                            app.errorMsg = response.data.message;
                        } else {
                            app.successMsg = response.data.message;
                            app.getAllUsers();
                        }
                    });
                },

                updateUser() {
                    var formData = app.toFormData(app.currentUser);
                    axios.post("http://localhost/crud-vue-php/process.php?action=update", formData).then(function(response) {
                        app.currentUser = {};
                        if (response.data.error) {
                            app.errorMsg = response.data.message;
                        } else {
                            app.successMsg = response.data.message;
                            app.getAllUsers();
                        }
                    });
                },

                deleteUser() {
                    var formData = app.toFormData(app.currentUser);
                    axios.post("http://localhost/crud-vue-php/process.php?action=delete", formData).then(function(response) {
                        app.currentUser = {};
                        if (response.data.error) {
                            app.errorMsg = response.data.message;
                        } else {
                            app.successMsg = response.data.message;
                            app.getAllUsers();
                        }
                    });
                },

                toFormData(obj) {
                    var fd = new FormData();
                    for (var i in obj) {
                        fd.append(i, obj[i]);
                    }
                    return fd;
                },
                selectUser(user) {
                    app.currentUser = user;
                },
                clearMsg() {
                    app.errorMsg = "";
                    app.successMsg = "";
                }


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

</html>

process.php

<?php
    $conn = new mysqli("localhost", "root", "", "crud_vue");
    if($conn->connect_error){
        die("Connection Failed!".$conn->connect_error);
    }
    //echo("Success");
    $result = array('error'=>false);
    $action = '';


    if(isset($_GET['action'])){
        $action = $_GET['action'];
    }



    if($action == 'read'){
        $sql = $conn->query("SELECT * FROM users");
        $users = array();
        while($row = $sql->fetch_assoc()){
            array_push($users, $row);
        }
        $result['users'] = $users;
    }


    if($action == 'create'){
        $name = $_POST['name'];
        $email = $_POST['email'];
        $phone = $_POST['phone'];

        $sql = $conn->query("INSERT INTO users (name,email,phone) VALUES('$name','$email','$phone')");
        
        if($sql){
            $result['message'] = "user added successfully!";
        }
        else{
            $result['error'] = true;
            $result['message'] = "failed to add user!";
        }
    }


    if($action == 'update'){
        $id = $_POST['id'];
        $name = $_POST['name'];
        $email = $_POST['email'];
        $phone = $_POST['phone'];

        $sql = $conn->query("UPDATE users SET name='$name', email='$email', phone='$phone' WHERE id='$id'");

        if($sql){
            $result['message'] = "user update successfully";
        }
        else{
            $result['error'] = true;
            $result['message'] = "failed to update user!";
        }
    }


    if($action == 'delete'){
        $id = $_POST['id'];

        $sql = $conn->query("DELETE FROM users WHERE id='$id'");

        if($sql){
            $result['message'] = "유저 삭제 성공했다!";
        }
        else{
            $result['error'] = true;
            $result['message'] = "유저 삭제 실패 ㅠㅠ!";
        }
    }

    $conn->close();
    echo json_encode($result);
    
?>

웹 개발을 할 때 form으로부터 전송 받은 값으 숫자인지 체크해야 할 때가 있다.

이럴 때는 간단하게 숫자체크를 하는 메소드를 공통 클래스에 포함 시켜 필요할 때마다 호출하여 사용한다.

익셉션을 이용한 숫자 체크 방법
숫자를 체크하는 방식은 Double.parseDouble 또는 Integer.parseInt를 활용하여 Exception을 통해 숫자여부를 판별


public class StringNumberCheck {
 
    public static void main(String[] args) {
 
        String str_1 = "가나다라" ;
        String str_2 = "523" ;
        String str_3 = "5.7" ;
        String str_4 = "-5" ;
        String str_5 = "-5.9" ;
         
        System.out.println(isNumber(str_1)) ;
        System.out.println(isNumber(str_2)) ;
        System.out.println(isNumber(str_3)) ;
        System.out.println(isNumber(str_4)) ;
        System.out.println(isNumber(str_5)) ;
        
    }
    // 익셉션에 걸린 다는 것은 잘못된 코드라는 뜻, 반대로 활용하면 숫자인지 아닌지 가려낸다.
    public static boolean isNumber(String str){
        boolean result = false;
        try{
            Double.parseDouble(str) ;
            result = true ;
        }catch(Exception e){}
     
        return result ;
    }

}

// 숫자 : true 아닐 경우 :false
출처: https://fruitdev.tistory.com/84 [과일가게 개발자]

https://fruitdev.tistory.com/84

 

[Java] 간단한 숫자체크

웹 개발을 할때 form 으로부터 전송받은 값이 숫자인지 체크해야 할 일이 종종 있다. 이럴때는 간단하게 숫자체크하는 메소드를 공통 클래스에 포함시켜 필요할때마다 호출해서 사용하면 편하다

fruitdev.tistory.com

 

 

Flask(웹 어플리케이션)과 Nginx(웹 서버)를 uWSGI(WSGI 인터페이스)를 이용하여 서로 연결하여 서비스를 할 수 있습니다.

 

WSGI(Web Server Gateway Interface)

- 웹서버와 웹 어플리케이션이 어떤 방식으로 통신하는가에 관한 인터페이스를 의미

- 웹서버와 웹어플리케이션 간의 소통을 정의해 어플리케이션과 서버가 독립적으로 운영될 수 있게 돕는다.

- WSGI 어플리케이션은 uWSGI라는 컨테이너에 담아 어플리케이션을 실행하게 되며, uWSGI가 각각의 웹서버와 소통하도록 설정하면 끝이다. Flask, django와 같은 프레임워크는 이미 WSGI 표준을 따르고 있기 때문에 바로 웹서버에 연결해 사용할 수 있다.

- WSGI는 파이썬 표준이며, 서버에서 들어온 요청에 맞춰서 파이썬 웹 어플리케이션에 미리 등록된 로직을 콜백 함수로 서버에 응답해줍니다. 여기서 WSGI 인터페이스에 맞춰서 제작된 프레임워크가 uWSGI입니다.

 

오래된 uwsgi를 삭제한다.
mv /usr/bin/uwsgi /usr/bin/uwsgi-old
 
새롭게 uwsgi를 설치해준다.
pip install uwsgi
ln -s /usr/local/bin/uwsgi /usr/bin/uwsgi

uwsgi로 해당 어플리케이션을 실행한다.
uwsgi -s /tmp/uwsgi.sock --module yourapplication --callable app --venv .venv


파라미터를 매번 입력하기 번거로우므로 다음과 같으 ini파일을 작성해 저장해 놓고 실행 할 수 있다.
[uwsgi]
chdir=/home/ubuntu/helloWorld
chmod-socket=666
callable=app
module=app
socket=/tmp/uwsgi.sock
virtualenv=/home/ubuntu/helloWorld/.venv


윗 처럼 작성한 후 다음 명령어로 실행한다.
 uwsgi <filename> &
 
 https://edykim.com/ko/post/connecting-flask-uwsgi-to-nginx/(출처)

nginx

- nginx는 기존의 apache같은 웹 서버입니다. 기존 apache 서버와 다른 점은 nginx 는 비동기 이벤트 기반으로 만들어졌고, apache 서버는 동기식, 프로세스 또는 쓰레드 기반으로 만들어졌습니다.
apache서버에 비해서메모리를 적게가져간다는 장점이 있습니다.

apt-get을 통해 설치
apt-get install nginx-full

/etc/nginx/sites-available/default 파일을 열어 설정을 해준다.
server {
        listen   8080;

        server_name helloworld.haruair.com;

        location / {
                try_files $uri @helloworld;
        }

        location @helloworld {
                include uwsgi_params;
                uwsgi_pass unix:/tmp/uwsgi.sock;
        }
}

위 설정을 통해 nginx로 들어오는 모든 요청을 uWSGI로 보내고 
또 돌려받아 nginx를 통해 클라이언트에 전달하게 된다. nginx를 재구동하면 적용된다.
/etc/init.d/nginx restart

https://medium.com/sunhyoups-story/flask-nginx-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95-258b979d2de3

 

Flask + Nginx 설치 방법

Flask와 Nginx를 uWSGI를 이용하여 연결해봅시다

medium.com

차이점 Apache vs Nginx

https://youngmind.tistory.com/entry/Apache-vs-Nginx

 

Apache vs Nginx

Apache vs Nginx  Apache와 Nginx는 현재까지 가장 폭넓게 사용되는 2가지의 오픈소스 웹서버이다. 2가지 솔루션들은 현재 전체 웹서비스의 50% 이상을 차지할 정도로 프론트엔드에서 사랑받고 있다. 이�

youngmind.tistory.com

정적 컨텐츠와 동적 컨텐츠의 차이점은 무엇입니까

https://presmarymethuen.org/ko/dictionary/what-is-the-difference-between-static-and-dynamic-content/

 

정적 컨텐츠와 동적 컨텐츠의 차이점은 무엇입니까

집 / 질문 / 정적 컨텐츠와 동적 컨텐츠의 차이점은 무엇입니까 정적 컨텐츠와 동적 컨텐츠의 차이점은 무엇입니까 대답 1: 정적 콘텐츠는 사이트를 방문하는 모든 사람에게 동일한 콘텐츠입니��

presmarymethuen.org

 

sqlarchemy

- Python의 객체에 데이터 모델을 정의하고 이를 데이터베이스와 매핑해주는 것을 ORM(Object Relaition Model)이라고 합니다. 덕분에 코드는 특정 데이터베이스에 종속되지 않고, 기본 객체 만으로 데이터를 기술할 수 있기 때문에 조금 더 OOP 스러운 코드를 작성할 수 있습니다.

Python에서 ORM으로 많이 쓰이는 것 중 SQLAlchemy가 있는데, 이를 Flask에서 플러그인 처럼 사용하기 쉽게 만들어진 Flask-SQLALchemy가 있습니다.

패키지 설치
(venv) PS flask_blog> pip install flask_sqlalchemy

https://opentutorials.org/module/3669/22070

 

데이터베이스 - Flask로 만드는 블로그

이전 시간에 우리는 부트스트랩을 이용해서 어플리케이션의 디자인을 조금 세련되게 변경했습니다. 이번에는 사용자와 게시물에 대한 정보를 저장하기 위한 데이터베이스를 만들어보도록 하��

opentutorials.org

 

개념 정의

  • 소프트웨어의 기획 의도나 목적에 따라 올바르게 구동하는가를 테스팅하여 제품의 이슈와 결함을 발견하고 제품의 품질을 높이는 것
  • 단계 : 테스트 계획 수립 > 분석 > 테스트케이스 작성 > 시행

테스트 분류

블랙박스 테스트 설명

소프트웨어의 내부 구조나 작동 원리를 모르는 상태에서 동작을 검사하는 방식이다.

사용자가 직접 특정 App이나 Device를 가지고 이리저리 작동시키는 과정이 블랙박스 테스트와 동일하다.

즉, 내부에 어떤 내용이 있는지 하나도 모른 채, 내가 원하는 기능이 예측한대로 정상 동작 하는지를 확인하는 방식이다.

즉, 사용자가 소프트웨어 또는 제품에 대한 요구사항과 결과물이 일치하는 지 확인하기 위한 테스트 기법

(사용자 관점의 테스트 방법)

화이트박스 테스트 설명

응용 프로그램의 내부 구조, 동작을 디테일하게 검사하는 테스트 방식이다.

디테일하게라는 의미는 내부 소스 코드를 테스트 하는 기법이며 사용자가 들여다 볼 수 없는 구간의 코드 단위들을 테스트 할 수 있다.(ex : private variable or method etc...)

즉, 개발자가 소프트웨어 또는 컴포넌트 등의 로직에 대한 테스트를 수행하기 위해 설계 단계에서 요구된 사항을 확인하는 테스트 기법 (개발자 관점의 단위 테스팅 기법)

블랙박스 테스트 vs 화이트박스 테스트

':: IT > 기술면접' 카테고리의 다른 글

웹개발3  (0) 2020.08.10
웹개발2  (0) 2020.08.10
웹개발  (0) 2020.08.10
파이썬 개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31

Jinja2의 정의

  • Jinja2는 파이썬에서 가장 많이 사용되는 템플릿 엔진 중 하나입니다. Django의 템플릿 시스템에서 영감을 얻었지만 템플릿 작상자에게 더 강력한 도구 세트를 제공하는 표현 언어로 확장했습니다. 또한 보안이 중요한 애플리케이션을 위해 샌드박스 실행 및 선택적 자동 이스케이프를 추가합니다.

Flask 템플릿 렌더링 방법

  • 기본적으로 Flask는 애플리케이션 폴더 안에 위치한 templates 서브폴더에서 템플릿을 검색한다.
  • 그 곳에 위치한 HTML 파일을 이용하여 렌더링 한다.

**예제 코드** from flask import Flask, render_template #... @app.route('/user/<name>') def user(name): return render_template('user_html', name=name)

예제 코드
from flask import Flask, render_template
#...
@app.route('/user/<name>')
def user(name):
  return render_template('user_html', name=name)

템플릿 엔진의 정의

  • 서버에서 받아온 데이터를 효과적으로 보여줄 중간 매체
  • 템플릿 엔진을 사용하면 비교적 간략한 표현(조건문, 변수 , 반복문)을 통해 효과적으로 데이터를 가공하여 웹페이지를 보여 줄 수 있다.

템플릿 엔진 설명의 예시

 

템플릿 엔진을 사용하는 이유

  1. 재사용성이 높다.

    웹페이지 혹은 웹앱을 만들 때 똑같은 디자인의 페이지에서 보이는 데이터만 바뀌는 경우가 많다.한 페이지를 템플릿 엔진 문법으로 만들어 놓고 여기에 데이터를 바꿔가면서 렌더링을 해주면 수 백의 페이지들을 나타낼수 있다.

  2. 유지보수에 용이하다

    템플릿 엔진을 사용하면 동일한 템플릿을 사용한다는 전제하에 템플릿과 넘겨주는 데이터만 수정하면 된다.

  3. 코드를 많이 줄일 수 있다.

    대부분의 템플릿 엔진은 기존의 HTML에 비해서 간단한 문법을 사용한다. 코드가 길어지면 길어질 수록 템플릿 엔진을 사용하면 좋다.

템플릿 사용의 예시

 

Jinja2의 기본 문법

{{ . . . }}

변수 나 표현식

**{{ . . . }} 사용의 예시** **변수의 예시** {% for head in table['thead'] %} <th>{{ head }}</th> {% endfor %} **표현식의 예시** <h1 class="h3 mb-2 text-gray-800">{{ page['manager.index'].get('title') }}</h1> <p class="mb-4">{{ page['manager.index'].get('sub_title') }}</p>

{{ . . . }} 사용의 예시

변수의 예시
{% for head in table['thead'] %}
<th>{{ head }}</th>
{% endfor %}

표현식의 예시
<h1 class="h3 mb-2 text-gray-800">{{ page['manager.index'].get('title') }}</h1>
<p class="mb-4">{{ page['manager.index'].get('sub_title') }}</p>

 

{% . . . %}

if나 for 같은 제어문

**{%. . . %} 사용의 예시** {% for i in range(body|length) %} <tr> {% set index = body[0] %} {% for i in range(body|length) %} {% if i == 1 %} <td> <a href="{{ url_for('manager.item', id=[index]) }}"> {{ body[i] }} </a> </td> {% else %} <td> {% if body[i] == '' %} - {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %} </td> {% endif %} {% endfor %} </tr> {% endfor %}

{%. . . %} 사용의 예시

{% for i in range(body|length) %}
				<tr>
				    {% set index = body[0] %}
				    {% for i in range(body|length) %}
				        {% if i == 1 %}
				            <td>
				                <a href="{{ url_for('manager.item', id=[index]) }}">
				                    {{ body[i] }}
				                </a>
				            </td>
				        {% else %}
				            <td>
				                {% if body[i] == '' %}
				                    -
				                {% else %}
				                    {{ body[i]|replace('\n', '<br>')|safe }}
				                {% endif %}
				            </td>
				        {% endif %}
				    {% endfor %}
				</tr>
{% endfor %}

{# . . . #}

주석문

{# . . . #} **사용의 예시** <head> {# 주석문입니다 #} {% block header %} {% include '_common/header.html' %} {% endblock %} </head>

{# . . . #} 사용의 예시

<head>
		{# 주석문입니다 #}
    {% block header %}
        {% include '_common/header.html' %}
    {% endblock %}
</head>

필터

  • Jinja2는 어떠한 타입의 변수라도 인식한다. (예 :리스트, 딕셔너리, 오브젝트 등)
  • 변수는 필터를 사용하여 수정 할 수 있으며 | 기호를 분리자로 하여 추가한다.

필터 관련 정보

필터 사용의 예시

**safe의 예시** <label class="col-sm-{{ label_size }} col-form-label {% if is_required %}required{% endif %}"> {{ label|safe }} </label> **replace와 safe의 예시** {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %} **length의 예시** {%for i in range(body|length)%} {% if i == 0 %}

safe의 예시
<label class="col-sm-{{ label_size }} col-form-label {% if is_required %}required{% endif %}">
    {{ label|safe }}
</label>
replace와 safe의 예시
{% else %}
	{{ body[i]|replace('\n', '<br>')|safe }}
{% endif %}
length의 예시
{%for i in range(body|length)%}
	{% if i == 0 %}

제어구조

if문

**if문의 구조** {% if <조건> %} <실행코드> {% elif <조건> %} <실행코드> {% else %} <실행코드> {% endif %} **if문의 예시** {% if body[i] == '' %} - {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %}

if문의 구조

{% if <조건> %}
	<실행코드>
{% elif <조건> %}
	<실행코드>
{% else %}
	<실행코드>
{% endif %}
if문의 예시

{% if body[i] == '' %}
    -
{% else %}
    {{ body[i]|replace('\n', '<br>')|safe }}
{% endif %}

for문

**for문의 구조** {% for <개별요소> in <리스트> %} <실행코드> {% endfor %} **for문의 예시** {% for body in table['tbody'] %} <tr> {% set index = body[0] %} {% for i in range(body|length) %} {% if i == 1 %} <td> <a href="{{ url_for('manager.item', id=[index]) }}"> {{ body[i] }} </a> </td> {% else %} <td> {% if body[i] == '' %} - {% else %} {{ body[i]|replace('\\n', '<br>')|safe }} {% endif %} </td> {% endif %} {% endfor %} </tr> {% endfor %}

for문의 구조

{% for <개별요소> in <리스트> %}
	<실행코드>
{% endfor %}
for문의 예시

{% for body in table['tbody'] %}
    <tr>
        {% set index = body[0] %}
        {% for i in range(body|length) %}
            {% if i == 1 %}
                <td>
                    <a href="{{ url_for('manager.item', id=[index]) }}">
                        {{ body[i] }}
                    </a>
                </td>
            {% else %}
                <td>
                    {% if body[i] == '' %}
                        -
                    {% else %}
                        {{ body[i]|replace('\n', '<br>')|safe }}
                    {% endif %}
                </td>
            {% endif %}
        {% endfor %}
    </tr>
{% endfor %}

include

css 나, 자바스크립트를 가져오는 header의 부분이나 상단의 navigation 부분, 하단의 footer 부분이 그러한데 일일히 모든 템플릿에 넣어 주기는 힘들다. 그래서 jinja2 에서는{% include %} 를 통해서 하나의 html 에서 다른 html 을 가져 올 수 있도록 해준다. 단순히 가져오는 것이라고 생각 할 수 있지만 내부적으로는 랜더링된 결과를 리턴한다고 한다.

  • include의 다른 형태

리스트의 형태로 template를 지정할 수 있다. 첫번째 HTML파일을 찾지 못하면 두번째 HTML 파일을 보여주고 두번째 파일도 없고 ignore missing 이라는 옵션이 켜져있으면 에러를 내뱉지 않는다.

{% include ['첫번째.html', '두번째.html'] %} {% include ['첫번째.html', '두번째.html'] ignore missing %}

{% include ['첫번째.html', '두번째.html'] %}

{% include ['첫번째.html', '두번째.html'] ignore missing %}

 

block/extends(템플릿의 상속)

flask 템플릿은 계층 구조를 지원한다. 하나의 웹사이트는 일반적으로 동일한 테마를 갖는다. 각각의 페이지는 동일한 구성요소를 갖는데 이를 매번 html 파일에 삽입하게 되면 구성요소를 변경할 때, 모든 파일에 수정사항을 반영해야 한다.

사용되는 동일한 구성요소는 base.html파일에 넣어두고, 나머지 페이지들은 이를 상속(extends) 받아서 사용하도록 하였다. 이를 통해 base.html 파일 하나를 변경함으로써 전 페이지에 변경사항을 적용할 수 있다.

 

기타 템플릿

커스텀 에러 페이지

에러에 대해 커스텀 핸들러를 제공하는 예제 코드는 아래와 같다.

**기본형태** @app.errorhandler(404) def page_not_found(e): return render_template('404.html'), 404

아래는 BS Traders의 응용코드의 예시이다. 404.html을 만들어 404에러시 띄울 수 있다.

**응용 형태** @web.app_errorhandler(404) def page_not_found(e): if request.accept_mimetypes.accept_json and \\ not request.accept_mimetypes.accept_html: response = jsonify({'error': 'not found'}) response.status_code = 404 return response return render_template('error/layout.html', contents='error/404.html'), 404 **404.html** <!-- 404 Error Text --> <div class="text-center"> <div class="error mx-auto" data-text="404">404</div> <p class="lead text-gray-800 mb-5">Page Not Found</p> <p class="text-gray-500 mb-0">{{ info }}</p> <a href="/">&larr; Back to Home</a> </div>

기본형태
@app.errorhandler(404)

def page_not_found(e):

return render_template('404.html'), 404
응용 형태
@web.app_errorhandler(404)
def page_not_found(e):
    if request.accept_mimetypes.accept_json and \
            not request.accept_mimetypes.accept_html:
        response = jsonify({'error': 'not found'})
        response.status_code = 404
        return response
    return render_template('error/layout.html',
                           contents='error/404.html'), 404
404.html
<!-- 404 Error Text -->
<div class="text-center">
    <div class="error mx-auto" data-text="404">404</div>
    <p class="lead text-gray-800 mb-5">Page Not Found</p>
    <p class="text-gray-500 mb-0">{{ info }}</p>
    <a href="/">&larr; Back to Home</a>
</div>

링크/정적파일

url_for()

템플릿에 직접 링크하는 것 처럼 URL을 작성하는 것은 간단한 라우팅 방법이지만 , 이는 원하지 않는 의존성을 생성하여 링크가 깨질 수 있다. 이러한 문제를 해결하기 위해 플라스크에서는 url_for() 헬퍼 함수를 제공하여 애플리케이션 URL맵에 저장된 정보를 통해 URL을 생성한다.

**기본형태** url_for('index') # '/' url_for('index', _external=True) # '<http://localhost:5000>' url_for('user', name='john', _external=True) # '<http://localhost:5000/user/john>' url_for('index', page=2) # '/?page=2' **예시** <form method="post" action="{{ url_for('buyer.new') }}"> ***정적인 파일도 url_for()을 사용해 불러 올 수 있다.** <link href="{{ url_for('static', filename='vendor/datatables/dataTables.bootstrap4.min.css') }}" rel="stylesheet">

기본형태
url_for('index') # '/'
url_for('index', _external=True) # 'http://localhost:5000'
url_for('user', name='john', _external=True) # 'http://localhost:5000/user/john'
url_for('index', page=2) # '/?page=2'

예시
<form method="post" action="{{ url_for('buyer.new') }}">

*정적인 파일도 url_for()을 사용해 불러 올 수 있다.
<link href="{{ url_for('static', filename='vendor/datatables/dataTables.bootstrap4.min.css') }}" rel="stylesheet">

 

물리계층(Layer 1)

  • 물리적 매체를 통해서 데이터 비트를 전송하기 위해 요구 되는 기능들을 정의하며 케이블 연결 장치 등 전송에 필요한 두 장치 간의 실제 접촉과 같은 기계적, 전기적 특성에 대한 규칙을 정의 한다.
    • 전송 단위 : 프레임(Frame) 프로토콜 : 이더넷, MAC, PPP 등 장비 : 브릿지 스위치

데이터 링크 계층(Layer 2)

  • 두 개의 개방 시스템들 간의 효율적이고 신뢰성 있는 정보 전송을 할 수 있도록 하며 오류의 검출과 회복을 위한 오류 제어 기능을 수행한다. 또한, 송신측과 수신측의 속도 차이를 해결하기 위해 흐름 제어(stop-and-wait & sliding window 방식으로 처리할 수 있는 패킷의 양보다 많은 경우) 기능을 하며 프레임의 시작과 끝을 구분하기 위한 프레임의 동기화 기능을 수행한다.
    • 전송단위 : 프레임(Frame) 프로토콜 : 이더넷, MAC, PPP 등 장비 : 브릿지, 스위치

네트워크 계층(Layer 3)

  • 다중 네트워크 링크에서 발신자로부터 목적지까지 책임을 가진다. 이전 계층인 데이터 계층은 노드 vs 노드 전달을 감독하는 것이고 네트워크 계층은 시작점에서 목적지까지 성공적으로 전달 되도록 하는 역할을 수행한다.
    • 전송단위 : 패킷(Packet) 프로토콜 : IP, ICMP 등 장비 : 라우터, L3 스위치

전송 계층(Layer 4)

  • 전체 메시지를 종단 vs 종단(End-to-End, 발신지에서 목적지)간 제어와 에러를 관리한다. 패킷의 전송이 유효한지 확인하고 전송에 실패된 패킷을 다시 보내는 것과 같은 신뢰성있는 통신을 보장한다. 주소 설정, 오류 및 흐름 제어, 다중화를 수행한다.
    • 전송단위 : 세그먼트(Segment) 프로토콜 : TCP, UDP 등 장비 : 게이트웨이, L4 스위치

세션 계층(Layer 5)

  • 양 끝단의 응용 프로세스가 통신을 관리하기 위한 방법을 제공한다. 동시송수신(Duplex), 반이중(Half-Duplex), 전이중(Full-Duplex) 방식의 통신과 함께 체크 포인팅과 유후, 종료, 다시 시작 과정 등을 수행한다. 통신 세션을 구성하며 포트 번호를 기반으로 연결한다.
    • 프로토콜 : NetBIOS, SSH, TLS

표현 계층(Layer 6)

  • 응용 계층으로부터 받은 데이터를 하위 계층인 세션 계층에 보내기 전에 통신에 적당한 형태로 변환하고 세션 계층에서 받은 데이터는 응용 계층에 맞게 변환하는 역할을 수행한다. 코드 변환, 구문 검색, 데이터 압축 및 암호화 등의 기능을 담당한다.
    • 프로토콜 : JPG, MPEG, SMB, AFP

응용 계층(Layer 7)

  • 응용 프로세스와 직접 관계하여 일반적인 응용 서비스를 수행한다. 응용 프로세스 간의 정보 교환, 전자메일, 파일전송 등의 서비스를 제공한다.
    • 프로토콜 : DNS, FTP, HTTP
  •  

HTTPS 프로토콜이란?

  • 웹 브라우저와 웹서버 간에 메세지 교환 프로토콜. 즉, 일종의 대화 규칙이며, 교환 방식은 복잡한 바이너리 데이터가 아닌 단순 텍스트를 통해 이루어진다.
  • HTTP의 취약점(보안문제)을 보완하기 위해 주고받는 모든 메시지를 SSL 프로토콜로 암호화하며, 암호화 방식에 쓰이는 Key의 종류로는 크게 대칭과 비대칭 둘로 나뉘게 된다.

대표적인 웹 보안 취약점


1. 인젝션(Injection)

  • SQL 인젝션, OS 인젝션 등의 취약점은 신뢰할 수 없는 데이터가 서버로 전달되는 명령어의 일부로서 보내질 때 발생할 수 있다. 공격자의 악의적인 데이터는 예상하지 못하는 결과를 초래할 수 있다. 예를 들어 데이터베이스에서 회원 정보를 전부 가져오도록 인젝션을 날릴 수도 있다.
  •  

위의 만화에 대해 설명하자면, 저 학교에서 입력한 명령은 다음과 같을 것이다.

INSERT INTO students (이름) VALUES ('학생 이름');

여기서 "Robert'); DROP TABLE students;--"학생을 "학생 이름" 자리에 넣을 경우 다음과 같은 명령문이 된다.

INSERT INTO students (이름) VALUES ('Robert');DROP TABLE students;--');

첫 번째 줄에서는 Robert라는 학생이 입력되었지만, 두 번째 줄에서 학생들의 데이터가 있는 테이블을 제거한다. 그리고 세 번째에서는 뒤에 오는 내용을 모두 주석 처리한다. 결과적으로 ‘모든 학생 기록을 삭제한다.’라는 뜻의 명령문이 완성된다.

  • 인젝션 공격 같은 경우는 공격 난이도가 낮은 데 반해서 공격 피해가 심각하다는 점에서 굉장히 중요하다.

2. 인증 및 세션관리 취약점

  • 인증이나 세션 관리가 제대로 되어 있지 않은 웹 애플리케이션의 경우 공격자에게 취약한 세션 값을 제공하여 다른 사람의 권한을 얻도록 할 수 있다. 예를 들어 인증 관리에서 실수를 하여 쿠키 값을 변조했더니 다른 사람의 아이디로 로그인이 되거나 하는 경우가 실제로도 비일비재한다. 다른 사용자의 권한을 얻을 수 있다는 점에서 개인 정보 등의 측면에서 굉장히 위협적인 공격이 될 수 있다.

다음의 사례가 대표적인 취약점 사례이다.

  1. 사용자 인증 정보가 저장될 때 해시 혹은 암호화를 사용하여 보호되지 않을 때

  2. 세션 ID가 성공적인 로그인 이후에 교체되지 않을 때

  3. 아이디, 비밀번호, 세션 ID 등이 암호화되지 않은 연결을 통해서 전송될 때

  4. 세션 ID가 URL에 노출될 때

  • 예를 들어 URL에 자신의 세션 ID가 그대로 노출되어 있는 상황이지만 클라이언트는 이를 인지하지 못하고 친구에게 해당 URL 정보를 보낼 수 있습니다. 이 때 친구는 URL을 확인하고 해당 세션으로 로그인을 할 수도 있는 것이다.
  • 공격의 난이도는 평균적인 수준이지만 영향도는 인젝션(Injection) 공격과 마찬가지로 심각한 수준에 이른다.

3. 크로스 사이트 스크립팅(XSS)

  • XSS 공격은 웹 사이트에서 서버와 통신하는 부분에서 스크립트 문장을 심어서 공격을 하는 해킹 유형이다. 대표적으로 게시판의 게시글을 작성했을 때 서버 단에서 사용자가 입력한 게시글의 정보를 제대로 필터링 하지 않거나 아예 필터링을 하지 않는 경우 다양한 특수 문자를 포함한 스크립트 문장을 심어서 서버로 전송할 수 있다. 이러한 방법을 악용하여 다양한 공격이 가능하다.

다음 사례가 대표적인 취약점 사례이다.

**String page += request.getParameter("boardContent");**

  • 위와 같은 경우 사용자는 boardContent라는 이름의 파라미터 변수에 스크립트 문장을 심어서 전송할 수 있고 서버는 제대로 이것을 필터링하지 않기 때문에 해킹이 제대로 적용될 수 있다. 대표적인 예시로 사용자는

 

데이터베이스의 정규화와 역정규화


정규화

  • 관계형 데이터베이스의 설계에서 중복을 최소화하게 데이터를 구조화하는 프로세스를 정규화(Normalization)라고 한다.

역정규화

  • 정규화된 데이터베이스에서 성능을 개선하기 위해 사용되는 전략을 역정규화(Denormalization)라고 한다.

데이터베이스의 인덱스 종류


1. 고유 인덱스(Unique Index)

  • 고유 인덱스는 유일한 값을 갖는 컬럼에 대해서 생성하는 인덱스로 고유 인덱스를 지정하려면 UNIQUE 옵션을 지정해야 한다.

SQL> CREATE **UNIQUE** INDEX idx_ukempno_emp ON emp(empno);

2. 단일 인덱스(Single Index)

  • 단일 인덱스는 한 개의 컬럼으로 구성한 인덱스를 말한다.

SQL> CREATE INDEX idx_ukempno_emp ON emp(empno);

3. 결합 인덱스(Composite Index)

  • 결합 인덱스는 두 개 이상의 컬럼으로 인덱스를 구성하는 것을 말합니다. 부서 번호와 부서명을 결합하여 인덱스를 설정 해 보도록 하겠다.

SQL> CREATE INDEX idx_dept_com ON index_dept(deptno, dname);

4. 함수 기반 인덱스(Function Based Index)

  • 함수 기반 인덱스는 SAL*12와 같이 컬럼에 어떠한 산술식을 수행했을때를 말한다.
  • SAL컬럼에 INDEX가 걸려있다해도 SAL*12은 INDEX를 타지 못합니다. 이럴때 함수 기반 인덱스를 생성한다.

SQL> CREATE INDEX idx_annsal_emp ON emp(sal*12);

데이터베이스의 좋은 인덱스 설계란?


- 인덱스 설계시 중요한 두 가지 선택 기준 1. 조건절에 항상 사용되거나, 자주 등장하는 컬럼들을 선정한다. 2. '='조건으로 자주 조회되는 칼럼들을 앞쪽에 둔다.

데이터베이스 실행 계획이란?


실행 계획의 정의

  • 실행계획(Execution Plan)이란 SQL에서 요구한 사항을 처리하기 위한 절차와 방법을 의미한다.
  • 동일한 SQL에 대해 결과를 낼 수 있는 다양한 처리 방법(실행계획)이 존재할 수 있지만 각 처리 방법마다 실행 시간(성능)은 서로 다를 수 있다.
  • 옵티마이저는 다양한 처리 방법들 중에서 가장 효율적인 방법을 찾아준다.(최적의 실행계획을 생성)

실행 계획의 구성 요소

  1. 조인순서(Join Order)

수행할 때 참조하는 테이블의 순서가

FROM A INNER JOIN B

일 때, 조인 작업을 위해 먼저 A테이블을 읽고 B 테이블을 읽는 작업을 수행한다면 조인 순서는 A -> B이다.

(논리적으로 가능한 조인순서는 n! 만큼 존재, n 은 FROM 절 다음에 나온 테이블 수)

  1. 조인 기법(Join Method)

두 개의 테이블을 조인할 때 사용할 수 있는 방법

NL Join, Hash Join, Sort Merge Join 등이 존재

  1. 액세스 기법(Access Method)

하나의 테이블을 액세스할 때 사용할 수 있는 방법

인덱스를 이용하는 인덱스 스캔(Index Scan)과 테이블 전체를 모두 읽는 전체 테이블 스캔(Full Table Scan) 등이 존재

  1. 최적화 정보(Optimization Information)

옵티마이저가 실행계획의 각 단계마다 예상되는 비용 사항을 표시한 것

최적화 정보에는 Cost, Card, Bytes가 존재

Cost : 상대적인 비용 정보

Card : Cardinality의 약자로서 주어진 조건을 만족한 결과 집합 혹은 조인 조건을 만족한 결과 집합의 건수를 의미

Bytes: 결과 집합이 차지하는 메모리 양을 바이트로 표시한 것

  1. 연산(Operation)

여러 가지 조작을 통해서 원하는 결과를 얻어내는 일련의 작업

연산에는 조인 기법, 액세스 기법, 필터, 정렬, 집계, 뷰 등 다양한 종류가 존재

':: IT > 기술면접' 카테고리의 다른 글

SW 테스트 방법론  (0) 2020.08.10
웹개발2  (0) 2020.08.10
웹개발  (0) 2020.08.10
파이썬 개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31

Ajax란?


  • 기존의 웹브라우저는 전자 문서를 염두에 두고 고안된 시스템이기 때문에 내용이 바뀌면 페이지 새로고침을 해서 내용을 새롭게 변경해야 되는 정적인 시스템이였다.

    그러다 Ajax 개념이 도입되면서 모든 것이 바뀌었다. Ajax는 웹브라우저와 웹서버가 내부적으로 데이터 통신을 하게 된다. 그리고 변경된 결과를 웹페이지에 프로그래밍적으로 반영함으로써 웹페이지의 로딩 없이 서비스를 사용할 수 있게 한다.

    Ajax는 Asynchronous JavaScript and XML의 약자다. 한국어로는 비동기적 자바스크립트와 XML 정도로 직역할 수 있는데 자바스크립트를 이용해서 비동기적으로 서버와 브라우저가 데이터를 주고 받는 방식을 의미한다. 이 때 사용하는 API가 XMLHttpRequest이다. 그렇다고 꼭 XML을 사용해서 통신해야 하는 것은 아니다. 사실 XML 보다는 JSON을 더 많이 사용한다.

HTTP 프로토콜이란?


  • 인터넷상에서 데이터를 주고 받기 위한 서버/클라이언트 모델을 따르는 프로토콜(상호 간에 정의한 규칙)이다.
  • 데이터를 주고 받기 위한 각각의 데이터 요청이 서로 독립적으로 관리가 된다. 즉 이전 데이터 요청과 다음 데이터 요청이 서로 관련이 없다.
  • 이러한 특징 덕택에 서버는 세션과 같은 별도의 추가 정보를 관리하지 않아도 되고, 다수의 요청 처리 및 서버의 부하를 줄일 수 있는 성능 상의 이점이 생긴다.
  • HTTP 프로토콜은 일반적으로 TCP/IP 통신 위에서 동작하며 기본 포트는 80번이다.

HTTP 접근 제어(CORS)란?


CORS는 무엇인가?

  • 다른 도메인으로부터 요청될 경우, 일반적인 HTTP 요청이 아닌 cross-origin HTTP 요청으로 처리하게 된다.
  • 브라우저는 보안상의 이유로 cross-origin HTTP 요청을 제한하게 된다.
  • 이유는 단순히 same-origin 정책이다.
  • 이러한 불편함으로 인해, 시간이 지나 W3C에서 대안으로 CORS 메커니즘을 내놓은 것이다.

CORS는 어떻게 동작되는 건가?

  • CORS는 라이브러리 혹은 구현 기술이 아닌 방침이라고 보면된다.
  • CORS는 브라우저의 정보를 읽을 수 있도록 서버에게 알려주도록 허용하는 HTTP 헤더를 추가함으로써 동작한다.

RESTful 설계란?


REST가 무엇인가?

  • REST는 분산 시스템 설계를 위한 아키텍처 스타일이다.
  • 아키텍처 스타일이라는건 쉽게 말하면 제약 조건의 집합이라고 보면 된다.
  • REST는 URI를 통해 자원을 표시하고, HTTP METHO를 이용하여 해당 자원의 행위를 정해주며 그 결과를 받는 것을 말한다.

RESTful은 무엇인가?

RESTful은 위의 제약 조건의 집합(아키텍처 스타일, 아키텍처 원칙)을 모두 만족하는 것을 의미한다.

REST라는 아키텍처 스타일이 있는거고 RESTful API라는 말은 REST 아키텍처 원칙을 모두 만족하는 API라는 뜻이다.

SQL Subquery란?


  • 쿼리 안에 있는 쿼리. Where/From/Select 절 안에 들어가는 쿼리.
  • 서브쿼리는 하나의 쿼리문 안에 포함된 또 하나의 쿼리문으로(중첩문) 메인쿼리가 서브쿼리를 포함하는 종속적 관계
  • 문법은 서브쿼리를 괄호로 묶어서 사용한다.
  • Order By절은 사용불가하며 연산자 오른쪽에 사용해야 한다.

서브쿼리의 반환값에 따른 서브쿼리

단일 행 서브쿼리 : 서브쿼리의 결과가 1행

다중 행 서브쿼리 : 서브쿼리의 결과가 여러 행

다중 컬럼 서브쿼리 : 서브쿼리의 결과가 여러 컬럼

SQL Join의 종류


두 개 이상의 테이블이나 데이터베이스를 연결하여 데이터를 검색한다.

보통 primary key 혹은 Foreign key로 두 테이블을 연결한다.

연결하려면 적어도 하나의 컬럼은 서로 공유 되고 있어야한다.

 

1) 이너 조인(Inner Join)

교집합. 기존 테이블과 조인한 테이블의 중복 값을 보여주는데 결과값은 교집합만 검색

Sele

ct <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Inner Join <조인테이블 별칭> On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> 예) Select A.NAME, B.AGE From EX_TABLE A Inner Join JOIN_TABLE B On A.NO_EMP = B.NO_EMP And A.NO_DEPT = B.NO_DEPT

Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Inner Join <조인테이블 별칭>
On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>

예)
Select
A.NAME, B.AGE From EX_TABLE A
Inner Join JOIN_TABLE B 
On A.NO_EMP = B.NO_EMP
And A.NO_DEPT = B.NO_DEPT

2) 아우터 조인(Left/Right Outer Join)

기존 테이블 값 + 교집합

Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Left Outer Join <조인테이블 별칭> On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> 예) Select A.NAME, B.AGE From EX_TABLE A Left Outer Join JOIN_TABLE B On A.NO_EMP = B.NO_EMP And A.NO_DEPT = B.NO_DEPT

Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Left Outer Join <조인테이블 별칭>
On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>

예)
Select
A.NAME, B.AGE From EX_TABLE A
Left Outer Join JOIN_TABLE B 
On A.NO_EMP = B.NO_EMP
And A.NO_DEPT = B.NO_DEPT

3) 풀 아우터 조인(Full Outer Join)

합집합

Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Full Outer Join <조인테이블 별칭> On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키> 예) Select A.NAME, B.AGE From EX_TABLE A Full Outer Join JOIN_TABLE B On A.NO_EMP = B.NO_EMP And A.NO_DEPT = B.NO_DEPT

Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Full Outer Join <조인테이블 별칭>
On <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>
And <기존테이블 별칭>.<기준키> = <조인테이블 별칭>.<기준키>

예)
Select
A.NAME, B.AGE From EX_TABLE A
Full Outer Join JOIN_TABLE B 
On A.NO_EMP = B.NO_EMP
And A.NO_DEPT = B.NO_DEPT

4) 크로스 조인(Cross Join)

모든 경우의 수(N*M)

Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭> Cross Join <조인테이블 별칭> 예) Select A.NAME, B.AGE From EX_TABLE A Cross Join JOIN_TABLE B

Select <별칭.칼럼>, <별칭.칼럼> From <기준테이블 별칭>
Cross Join <조인테이블 별칭>

예)
Select
A.NAME, B.AGE From EX_TABLE A
Cross Join JOIN_TABLE B 

5) 셀프 조인(Self Join)

하나의 테이블을 여러번 복사해서 조인

Select <별칭.칼럼>, <별칭.칼럼> From <테이블명 별칭1>, <테이블명 별칭2>

Select <별칭.칼럼>, <별칭.칼럼> From <테이블명 별칭1>, <테이블명 별칭2>

데이터베이스 트랜젝션이란?


  • 데이터베이스의 상태를 바꾸는 기능을 수행하기 위한 작업의 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산들을 의미
  • 모든 명령어의 성공 또는 실패를 한번에 처리 흔한 예로 계좌입금에서 일어날 수 있는 오류등을 생각해보면 좋다.
  • 하나의 트랜잭션으로 관리하면 계좌에 입금하는 기능이 실패 했을 경우, 철수의 계좌에서 돈이 다시 입금되어야한다.(이를 Rollback이라고 한다.)

데이터베이스의 외래키와 무결성 제약 조건


데이터베이스의 외래키

  • 외래키는 두 테이블을 서로 연결하는 데 사용되는 키
  • 외래키가 포함된 테이블을 자식 테이블이라고 하고 외래키 값을 제공하는 테이블을 부모 테이블이라한다.

MySQL: CREATE TABLE Orders ( OrderID int NOT NULL, OrderNumber int NOT NULL, PersonID int, PRIMARY KEY (OrderID), FOREIGN KEY (PersonID) REFERENCES Persons(PersonID) ); SQL Server / Oracle / MS Access: CREATE TABLE Orders ( OrderID int NOT NULL PRIMARY KEY, OrderNumber int NOT NULL, PersonID int FOREIGN KEY REFERENCES Persons(PersonID) );

MySQL:

CREATE TABLE Orders (
OrderID int NOT NULL,
OrderNumber int NOT NULL,
PersonID int,
PRIMARY KEY (OrderID),
FOREIGN KEY (PersonID) REFERENCES Persons(PersonID)
);
SQL Server / Oracle / MS Access:

CREATE TABLE Orders (
OrderID int NOT NULL PRIMARY KEY,
OrderNumber int NOT NULL,
PersonID int FOREIGN KEY REFERENCES Persons(PersonID)
);

무결성의 제약조건

  • 개체 : 테이블에 있는 모든 행들이 유일한 식별자를 가질 것을 요구한다.(같은 값 X)
  • 참조 : 외래키 값은 NULL이거나 참조 테이블의 PK값이여야함
  • 영역 : 한 칼럼에 대해 NULL 허용 여부와 자료형 , 규칙으로 타당한 데이터 값을 지정

':: IT > 기술면접' 카테고리의 다른 글

SW 테스트 방법론  (0) 2020.08.10
웹개발3  (0) 2020.08.10
웹개발  (0) 2020.08.10
파이썬 개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31

세션과 쿠키의 차이점


HTTP 프로토콜을 이용하게 되는 웹 사이트에서는 웹 페이지에 특정 방문자가 머무르고 있는 동안에 그 방문자의 상태를 지속시키기 위해 쿠키와 세션을 이용한다.

세션

  1. 특정 웹사이트에서 사용자가 머무르는 기간 또는 한명의 사용자의 한번의 방문을 의미한다.
  2. 세션에 관련된 데이터는 서버에 저장된다.
  3. 웹 브라우저의 캐시에 저정되어 브라우저가 닫히거나 서버에서 삭제 시, 사라진다.
  4. 쿠키에 비해 보안성이 좋다.

쿠키

  1. 사용자 정보를 유지할 수 없다는 HTTP의 한계를 극복 할 수 있는 방법이다.
  2. 인터넷 웹 사이트의 방문 기록을 남겨 사용자와 웹 사이트 사이를 매개해주는 정보이다.
  3. 쿠키는 인터넷 사용자가 특정 웹서버에 접속할 때, 생성되는 개인 아이디와 비밀번호, 방문한 사이트의 정보를 담은 임시파일로써, 서버가 아닌 클라이언트에 텍스트 파일로 저장되어 다음에 해당 웹서버를 찾을 경우 웹 서버에서는 그가 누구인지 어떤 정보를 주로 찾았는지 등을 파악할 때 사용 된다.
  4. 쿠키는 클라이언트 PC에 저장되는 정보이기 때문에, 다른 사용자에 의해서 임의로 변경이 가능하다.(정보유출 가능, 세션 보다 보안성이 낮은 이유)

Get과 Post의 차이점


Get

  • 클라이언트에서 서버로 데이터를 전달할 때, 주소 뒤에 "이름"과 "값"이 결합된 쿼리 스트링 형태로 전달한다.
  • 주소창에 쿼리 스트링이 그대로 보여지기 때문에 보안성이 떨어진다.
  • 길이에 제한이 있다.(전송 데이터에 한계가 있다.)
  • Post 방식보다 상대적으로 전송 속도가 빠르다.

Post

  • 일정크기 이상의 데이터를 보내야 할 때 사용한다.
  • 서버로 보내기 전에 인코딩하고, 전송 후 서버에는 다시 디코딩 작업을 한다.
  • 주소창에 전송하는 데이터의 정보가 노출 되지 않아 Get방식에 비해 보안성이 높다.
  • 속도가 Get방식보다 느리다.
  • 쿼리 스트링(문자열)데이터 뿐만 아니라, 라디오 버튼, 텍스트박스 같은 객체들의 값도 전송 가능하다.

차이점

  • Get은 주로 웹 브라우저가 웹 서버에 데이터를 요청 할 때 사용한다.
  • Post는 웹 브라우저가 웹 서버에 데이터를 전달하기 위 해 사용한다.
  • Get을 사용하면 웹 브라어저에서 웹서버로 전달되는 데이터가 인코딩 되어 URL에 붙는다.
  • Post 방식은 전달되는 데이터가 보이지 않는다.
  • Get 방식은 전달되는 데이터가 255개의 문자를 초과하면 문제가 발생할 수 있다.
  • 웹 서버에 많은 데이터를 전달하기 위해서는 Post방식을 사용하는 것이 바람직하다.

URL Encoding이란?


  • 문자나 특수문자를 웹 서버와 브라우저에서 보편적으로 허용되는 형식으로 변화하는 메커니즘이다.
  • URL은 ASCII 문자 집합을 사용하여 인터넷을 통해서만 전송할 수 있다.
  • URL은 종종 ASCII 세트 외부의 문자를 포함하기 때문에 URL은 유효한 ASCII 형식으로 변환되어야 한다.
  • URL 인코딩은 안전하지 않은 ASCII 문자를 "%" 다음에 두 개의 16진수로 대체한다.
  • URL은 공백을 포함할 수 없다. URL 인코딩은 일반적으로 공백을 더하기 (+) 기호 또는 % 20으로 바꾼다.
  • 고로, 아스키 이외의 문자는 다 인코딩 해야된다. (한글, 일본어, 중국어, 독일어, ... )

예) 안녕하세요 %ec%95%88%eb%85%95%ed%95%98%ec%84%b8%ec%9a%94

JSON이란?


  • JSON(JavaScript Object Notation)의 약자로 JavaScript에서 객체를 만들 때 사용하는 표현식을 의미한다. 이 표현식은 사람도 이해하기 쉽고 기계도 이해하기 쉬우면서 데이터의 용량이 작다. 이런 이유로 최근에는 JSON이 XML을 대체해서 설정의 저장이나 데이터를 전송등에 많이 사용된다.

{ "name": "식빵", "family": "웰시코기", "age": 1, "weight": 2.14 }

Jquery란?


  • 자바스크립트의 생산성을 향상시켜주는 자바스크립트 라이브러리이다.
  • 라이브러리란 자주 사용되는 로직들을 재활용, 유통 가능하도록 만든 로직들의 묶음을 의미합니다. 자바스크립트의 세계에는 많은 라이브러리들이 있다. prototype, jQuery, YUI 등등 구글트랜드로 검색을 해보면 현재는 jQuery가 가장 많은 사용자를 가지고 있다. jQuery를 이용하면 순수한 자바스크립트로 코딩하는 것 보다 10배 이상 생산성을 높일 수 있다. 또 jQuery는 파생된 라이브러리들을 가지고 있다. jQuery UI는 jQuery기반의 GUI 라이브러리이다. 이것을 이용해서 윈도우 에플리케이션과 같은 기능성의 UI를 만들 수 있다.
  • 최근에는 jQuery Mobile라는 이름의 모바일 라이브러리를 출시해서 모바일용 웹에플리케이션을 만드는데도 많은 도움을 주고 있다.

CSS의 미디어쿼리란?


  • 미디어 쿼리(mediaqueri)는 사이트에 접속하는 장치에 따라 특정한 CSS 스타일을 사용하도록 도와주는 소프트웨어 모듈이다. 미디어 쿼리를 이용한 사이트는 웹 사이트에 접속하는 기기에 따라서 레이아웃이 바뀌게 된다. 즉, PC로 접속하면 모니터 화면에 맞게, 스마트폰으로 접속하면 스마트폰 화면에 맞게 레이아웃이 변경되는 것이다. 웹 문서의 스타일을 정의할 때, 즉 CSS 코드를 작성할 때 미디어쿼리 모듈을 사용해 주는 것이 일반적인 사용 방법이다.

':: IT > 기술면접' 카테고리의 다른 글

웹개발3  (0) 2020.08.10
웹개발2  (0) 2020.08.10
파이썬 개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31
[기술면접] 운영체제  (0) 2020.07.31

Collection의 종류


Collection은 python에 내장된 일반 자료형의(dict, list, set, tuple) 컨테이너 타입을 조금 더 발전시킨 형태의 구현체이다.

Collection 종류

Decorator란?


대상 함수를 wrapping 하고, wrapping 된 함수의 앞뒤에 추가적으로 꾸며질 구문들을 정의하여 함수의 내부를 수정하지 않고 기능에 변화를 주고싶을때 사용한다. 반복되는 구문을 decorator 함수를 재사용 함으로써 가독성과 직관성을 올릴 수 있다.

리스트와 튜플의 차이점


리스트는 가변적이며 튜플은 불변적이다. 그렇기 때문에 튜플은 append() 메소드와 같이 데이터를 수정하는 메소드를 사용할 수 없다. 리스트는 주로 요소의 수가 명확하지 않은 경우에 사용하며, 튜플은 요소의 수를 정확히 알고 있을때 사용한다.

파이썬의 함수 파라미터 종류


https://wikidocs.net/16053

1. default value(기본값)

인자를 입력하면 입력한 값으로 변경이 되어 전달되며,

입력하지 않을경우 처음 설정한 value값이 전달된다.

def fun(a, b = value): ... fun('a',[인자])

def fun(a, b = value):
	...
fun('a',[인자])

2. positional argument(위치 인자)

함수에서 정의한 위치대로 인자를 전달한다.

def fun(a, b): ... fun('a','b')

def fun(a, b):
	...
fun('a','b')

3. keyword argument(키워드 인자)

함수를 정의할때 파라미터의 순서와 상관없이 키워드 인자를 사용해 값을 전달할 수 있다.

def fun(a, b): ... fun(b = 'b', a = 'a')

def fun(a, b):
	...
fun(b = 'b', a = 'a')

4. 위치 인자 언패킹

리스트나 튜플과 같이 원소가 존재하는 객체를 *을 붙여 인자로서 함수에 입력하면 함수의 정의된 위치에 맞게 전달된다.

def fun(a, b, c): ... p = [5, 7, 9] fun(*p) fun(*(5, 7, 9))

def fun(a, b, c):
	...
p = [5, 7, 9]
fun(*p)
fun(*(5, 7, 9))

5. 키워드 인자 언패킹

키와 값이 있는 dict타입의 변수에 **을 붙여 인자로서 함수에 입력하면 함수의 정의된 위치에 맞게 전달된다.

def fun(a, b, c): ... p = {'a' : 'A', 'b' : 'B', 'c' : 'C'} fun(**p) fun(**{'a' : 'A', 'b' : 'B', 'c' : 'C'})

def fun(a, b, c):
	...
p = {'a' : 'A', 'b' : 'B', 'c' : 'C'}
fun(**p)
fun(**{'a' : 'A', 'b' : 'B', 'c' : 'C'})

클래스 메소드란?


클래스 메소드는 클래스에서 호출되고 인스턴스 메소드가 첫번째 파라미터로 자신의 인스턴스를 self로 전달하는 것과 달리 자신의 클래스를 파라미터로 전달한다. 인스턴스 메소드에서는 인스턴스에 국한하여 데이터를 사용하지만 클래스 메소드는 인스턴스가 공유하는 클래스 데이터를 사용할 수 있다.

class Language: default_language = "English" def __init__(self): self.show = '나의 언어는' + self.default_language @classmethod def class_my_language(cls): return cls() @staticmethod def static_my_language(): return Language() def print_language(self): print(self.show) class KoreanLanguage(Language): default_language = "한국어" >>> from language import * >>> a = KoreanLanguage.static_my_language() >>> b = KoreanLanguage.class_my_language() >>> a.print_language() 나의 언어는English >>> b.print_language() 나의 언어는한국어

class Language:
    default_language = "English"

    def __init__(self):
        self.show = '나의 언어는' + self.default_language

    @classmethod
    def class_my_language(cls):
        return cls()

    @staticmethod
    def static_my_language():
        return Language()

    def print_language(self):
        print(self.show)


class KoreanLanguage(Language):
    default_language = "한국어"


>>> from language import *
>>> a = KoreanLanguage.static_my_language()
>>> b = KoreanLanguage.class_my_language()
>>> a.print_language()
나의 언어는English
>>> b.print_language()
나의 언어는한국어

 

Docstring란?


Docstring은 코드의 문서화에 도움이 되는 문자열이다. """ 주석 내용 """ 을 사용하여 작성하며 모듈 파일 처음이나 함수, 클래스 선언 다음라인에 주로 작성한다.

def docs(0): """ 주석내용 """ >> docs.__doc__ >> '주석내용'

def docs(0):
	"""
	주석내용
	"""

>> docs.__doc__
>> '주석내용'

Callable 객체란?


함수처럼 호출될 수 있는 객체이며, callable() 함수를 사용해서 객체가 callable 객체인지 확인할 수 있다.

class Accumulator(object): def __init__(self, n): self.n = n def __call__(self, x): self.n += x return self.n from_1 = Accumulator(1) from_10 = Accumulator(10) print(from_1(10)) print(from_10(200)) callable(from_1) >> 11 >> 210 >> True

class Accumulator(object):
    def __init__(self, n):
        self.n = n
    def __call__(self, x):
        self.n += x
        return self.n

from_1 = Accumulator(1)
from_10 = Accumulator(10)

print(from_1(10))
print(from_10(200))
callable(from_1)
>> 11
>> 210
>> True

GIL이란?


Global Interpreter Lock의 약자로 파이썬 인터프리터가 한 쓰레드만 하나의 바이트코드만 실행할 수 있게 하는것이다.

한 쓰레드가 자원을 점유하면 다른 쓰레드는 대기하고 자원 점유를 멈추면 또다른 쓰레드가 자원을 점유하게 되는데, 이때 각 쓰레드가 원하는 시점에서 GIL을 획득하지 못해 실행이 지연될 수 있다.

https://dgkim5360.tistory.com/entry/understanding-the-global-interpreter-lock-of-cpython

 

패키지 관리자란?


패키지 소프트웨어를 설치, 관리하는 시스템으로 대표적인 파이썬 패키지 관리자로는 pip이 있다.

가상 환경이란?


파이썬에서는 한 라이브러리에 하나의 버전만 설치가 가능하며 여러 프로젝트를 진행할때 다른 버전의 라이브러리를 사용한다면 문제가 되기때문에 프로젝트 마다 독립적인 가상환경을 만들어 패키지를 관리한다.

 

This wiki is built in Notion. Here are all the tips you need to contribute.

PEP-8 스타일 가이드란?


Python Enhancement Proposal의 약자로 특정 규칙을 따르며 다른 사람과 원활한 협업을 도와주고 가독성을 높여준다.

whitespace

  • 탭이 아닌 스페이스로 들여쓴다
  • 문법적으로 의미있는 들여쓰기(indenting)는 스페이스 네 개를 사용한다.
  • 한 줄의 문자 길이가 79자 이하여야 한다.
  • 한 파일에서 함수와 클래스는 빈 줄 두개로 구분해야 한다.
  • 클래스에서 메서드는 빈 줄 하나로 구분해야 한다.
  • 리스트 인덱스, 함수 호출, 키워드 인수 할당에는 스페이스를 사용하지 않는다.
  • 변수 할당 앞뒤에 스페이스를 하나만 사용한다.

Naming

  • Functions(함수), Variables(변수), Attributes(속성)은 lowercase_underscore 형식을 따른다.
  • Protected instance attributes는 _leading_underscore 형식을 따른다.
  • Private instance attributes는 __double_leading_underscore 형식을 따른다.
  • Class, Except는 CapitalizedWord 형식을 따른다.
  • 모듈에서의 상수는 ALL_CAPS 형식을 따른다.
  • 클래스의 메소드(함수)는 첫 번째 파라미터의 이름을 self로 지정한다.
  • 클래스 메소드에서는 첫 번째 파라미터의 이름을 cls로 지정한다.

Expressions and Statements

  • if len(somelist) == 0으로 빈 값([] or ' ')을 확인하지 않고, if not some somelist를 사용하여 빈 값은 False가 된다고 가정한다.
  • 반대로, 값이 있는경우([1] or 'hi') if somelist가 True가 된다.
  • 한 줄로 된 if문, for와 while 루프, except 복합문을 쓰지 않고, 여러 줄로 나눠서 명료하게 작성한다.
  • 항상 파일의 맨 위에 import 문을 놓는다.
  • import는 '표준 라이브러리 모듈, Third-Party 모듈, 자신이 만든 모듈' 순으로 구분해야 한다.

매직 메소드란?


클래스 안에 정의된 함수중 함수가 __로 시작해서 __로 끝나는 메소드를 매직 메소드 라고 부른다. 대표적인 매직 메소드로는 init, __call__등 이 있다.

이터레이터의 생성 방법


이터레이터는 반복가능한 객체(list, dict, set, ...)을 인자로 전달받아 사용하며 객체의 인덱스 위치를 저장하고 있다.

a = [1, 2, 3] a_iter = iter(a) a2_iter = a.__iter__()

a = [1, 2, 3]
a_iter = iter(a)
a2_iter = a.__iter__()

제네레이터와 코루틴이란?


제네레이터

return 키워드 대신 yield키워드를 사용하는 함수다. 배열이나 리스트와 같이 반복가능한 값들을 생성해내며 값을 반환할때 모든값을 반환하는 것이 아닌 한 개의 값을 반환한다.

def num_gen(): for i in range(3): yield i g = num_gen() # 제너레이터 객체 생성 num1 = next(g) num2 = next(g) num3 = next(g) print(num1, num2, num3)

def num_gen():
    for i in range(3):
        yield i


g = num_gen()       # 제너레이터 객체 생성 

num1 = next(g)
num2 = next(g)
num3 = next(g)

print(num1, num2, num3)

코루틴

제네레이터는 yield를 사용해서 값을 발생시키지만 코루틴은 제네레이터의 무한루프문 안에서 값을 전달받아 사용된다.

while True: # 코루틴을 계속 유지하기 위해 무한 루프 사용 x = (yield) # 코루틴 바깥에서 값을 받아옴, yield를 괄호로 묶어야 함 print(x) co = number_coroutine() next(co) # 코루틴 안의 yield까지 코드 실행(최초 실행) co.send(1) # 코루틴에 숫자 1을 보냄 co.send(2) # 코루틴에 숫자 2을 보냄 co.send(3) # 코루틴에 숫자 3을 보냄

while True:        # 코루틴을 계속 유지하기 위해 무한 루프 사용
        x = (yield)    # 코루틴 바깥에서 값을 받아옴, yield를 괄호로 묶어야 함
        print(x)
 
co = number_coroutine()
next(co)      # 코루틴 안의 yield까지 코드 실행(최초 실행)
 
co.send(1)    # 코루틴에 숫자 1을 보냄
co.send(2)    # 코루틴에 숫자 2을 보냄
co.send(3)    # 코루틴에 숫자 3을 보냄

 

파이썬에서의 메모리 추가/삭제 방법


파이썬은 가비지 컬렉션(Garbage Collection)이 메모리를 관리 해주기 때문에 사용자가 따로 관리할 필요가 없다. 가비지 컬렉션은 객체를 참조하는 다른 객체 또는 위치가 늘어날수록 해당 객체의 reference count는 증감하게 되고, reference count가 0이 되면 객체는 메모리에서 해제하는 식으로 메모리를 관리한다.

':: IT > 기술면접' 카테고리의 다른 글

웹개발2  (0) 2020.08.10
웹개발  (0) 2020.08.10
[기술면접] 데브옵스  (0) 2020.07.31
[기술면접] 운영체제  (0) 2020.07.31
[기술면접] 네트워크  (0) 2020.07.30

https://translate.google.com/translate?hl=ko&sl=en&u=https://flask-login.readthedocs.io/en/latest/&prev=search&pto=aueflask-login.readthedocs.io/en/latest/

 

Flask-Login — Flask-Login 0.4.1 documentation

Flask-Login Flask-Login provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering your users’ sessions over extended periods of time. It will: Store the active user’s ID in the session, and let

flask-login.readthedocs.io

플라스크 로그인 

Flask-Login은 Flask에 대한 사용자 세션 관리를 제공합니다. 오랜 시간 동안 로그인, 로그 아웃 및 사용자 세션 기억과 같은 일반적인 작업을 처리합니다.

그것은 :

  • 활성 사용자의 ID를 세션에 저장하고 쉽게 로그인 및 로그 아웃 할 수 있습니다.
  • 보기를 로그인 한 (또는 로그 아웃 한) 사용자로 제한 할 수 있습니다.
  • 일반적으로 까다로운 "기억하기"기능을 처리하십시오.
  • 쿠키 도둑이 사용자의 세션을 도난 당하지 않도록 보호합니다.
  • Flask-Principal 또는 다른 인증 확장 프로그램과 나중에 통합 할 수 있습니다.

그러나 다음과 같은 것은 아닙니다.

  • 특정 데이터베이스 나 다른 저장 방법을 사용하십시오. 사용자로드 방법에 대한 책임은 전적으로 귀하에게 있습니다.
  • 사용자 이름과 비밀번호, OpenID 또는 기타 인증 방법을 사용하도록 제한하십시오.
  • "로그인 여부"이외의 권한을 처리합니다.
  • 사용자 등록 또는 계정 복구를 처리합니다.

설치 

pip를 사용하여 확장을 설치하십시오.

$ pip install flask-login

귀하의 응용 프로그램 구성 

Flask-Login을 사용하는 응용 프로그램에서 가장 중요한 부분은 LoginManager클래스입니다. 다음과 같이 코드 어딘가에 응용 프로그램 용으로 하나를 만들어야합니다.

login_manager = LoginManager()

로그인 관리자에는 ID에서 사용자를로드하는 방법, 로그인해야 할 때 사용자를 보내는 위치 등과 같이 응용 프로그램과 Flask-Login이 함께 작동하도록하는 코드가 포함되어 있습니다.

실제 응용 프로그램 객체가 생성되면 다음을 사용하여 로그인하도록 구성 할 수 있습니다.

login_manager.init_app(app)

기본적으로 Flask-Login은 인증에 세션을 사용합니다. 즉, 응용 프로그램에서 비밀 키를 설정해야합니다. 그렇지 않으면 Flask가이를 알리는 오류 메시지를 표시합니다. 비밀 키를 설정하는 방법 은 세션  Flask 설명서 를 참조하십시오.

경고 : “좋은 비밀 키를 생성하는 방법”섹션에서 제공된 명령을 사용하여 자신의 비밀 키를 생성하십시오. 예제를 사용하지 마십시오.

그것이 작동하는 방법 

user_loader콜백 을 제공해야합니다 . 이 콜백은 세션에 저장된 사용자 ID에서 사용자 객체를 다시로드하는 데 사용됩니다. unicode사용자  ID를 가져와 해당 사용자 개체를 반환해야합니다. 예를 들면 다음과 같습니다.

@login_manager.user_loader def load_user(user_id): return User.get(user_id)

이것은 반환한다 None( 예외를 발생시키지 ID가 유효하지 않은 경우). 이 경우 세션에서 ID가 수동으로 제거되고 처리가 계속됩니다.

사용자 클래스 

사용자를 나타내는 데 사용하는 클래스는 다음 속성 및 메서드를 구현해야합니다.

is_authenticatedTrue사용자가 인증 된 경우, 즉 유효한 자격 증명을 제공 한 경우이 속성이 반환되어야합니다 . 인증 된 사용자 만의 기준을 충족합니다 login_required.is_active이 속성은 True활성 사용자 인 경우 인증되는 것 외에도 계정을 활성화했거나 일시 중지하지 않았거나 응용 프로그램이 계정을 거부 한 조건을 반환해야 합니다. 비활성 계정은 로그인 할 수 없습니다 (물론 강제로).is_anonymousTrue익명 사용자 인 경우이 속성이 반환되어야합니다 . (실제 사용자는 False대신 돌아와야 합니다.)get_id()이 메소드는 unicode이 사용자를 고유하게 식별하는 user_loader 콜백을 반환해야 하며 콜백 에서 사용자를로드하는 데 사용할 수 있습니다 . 참고이이 것을 해야한다  unicode- ID가 기본적 인 경우 int또는 다른 유형, 당신은으로 변환해야합니다 unicode.

사용자 클래스 구현을보다 쉽게하기 위해 from을 상속하면 UserMixin이러한 모든 속성 및 메서드에 대한 기본 구현이 제공됩니다. (필요하지는 않습니다.)

로그인 예 

사용자가 인증되면 login_user 기능 을 사용하여 로그인합니다 .

예를 들면 다음과 같습니다.

@app.route('/login', methods=['GET', 'POST']) def login(): # Here we use a class of some kind to represent and validate our # client-side form data. For example, WTForms is a library that will # handle this for us, and we use a custom LoginForm to validate. form = LoginForm() if form.validate_on_submit(): # Login and validate the user. # user should be an instance of your `User` class login_user(user) flask.flash('Logged in successfully.') next = flask.request.args.get('next') # is_safe_url should check if the url is safe for redirects. # See http://flask.pocoo.org/snippets/62/ for an example. if not is_safe_url(next): return flask.abort(400) return flask.redirect(next or flask.url_for('index')) return flask.render_template('login.html', form=form)

경고 : 반드시 next매개 변수 값을 확인해야합니다 . 그렇지 않으면 응용 프로그램이 열린 리디렉션에 취약합니다. 구현 예는 이 Flask Snippet  is_safe_url참조하십시오 .

그렇게 간단합니다. 그런 다음 current_user모든 템플릿에서 사용할 수 있는 프록시 를 사용하여 로그인 한 사용자에게 액세스 할 수 있습니다 .

{% if current_user.is_authenticated %} Hi {{ current_user.name }}! {% endif %}

사용자가 로그인해야하는 뷰는 login_required데코레이터 로 장식 할 수 있습니다 .

@app.route("/settings") @login_required def settings(): pass

사용자가 로그 아웃 할 준비가되면 :

@app.route("/logout") @login_required def logout(): logout_user() return redirect(somewhere)

로그 아웃되고 세션에 대한 쿠키가 정리됩니다.

로그인 프로세스를 정의 

기본적으로 사용자 login_required가 로그인하지 않고보기 에 액세스하려고하면 Flask-Login이 메시지를 깜박이고 로그인보기로 리디렉션합니다. (로그인보기가 설정되어 있지 않으면 401 오류와 함께 중단됩니다.)

로그인보기의 이름은로 설정할 수 있습니다 LoginManager.login_view. 예를 들면 다음과 같습니다.

login_manager.login_view = "users.login"

깜박이는 기본 메시지는 메시지 를 사용자 정의하려면 다음을 설정하십시오 .Please log in to access this page.LoginManager.login_message

login_manager.login_message = u"Bonvolu ensaluti por uzi tiun paĝon."

메시지 카테고리를 사용자 정의하려면 LoginManager.login_message_category다음을 설정하십시오 .

login_manager.login_message_category = "info"

로그인보기가 경로 재 지정 될 next때 사용자가 액세스하려고하는 페이지 인 조회 문자열에 변수가 있습니다. 경우 또는 USE_SESSION_FOR_NEXT이다 True페이지는 키 아래 세션에 저장됩니다 next.

프로세스를 추가로 사용자 정의하려면 LoginManager.unauthorized_handler다음을 사용 하여 함수를 장식하십시오 .

@login_manager.unauthorized_handler def unauthorized(): # do stuff return a_response

인증 헤더를 사용하여 로그인 

주의

이 방법은 더 이상 사용되지 않습니다. request_loader 대신 아래를 사용하십시오 .

때로는 Authorization API 요청과 같은 헤더를 사용하여 기본 인증 로그인을 지원하려고 합니다. 헤더를 통한 로그인을 지원하려면 header_loader콜백 을 제공해야합니다 . 이 콜백은 user_loader사용자 ID 대신 헤더 값을 허용한다는 점을 제외하면 콜백 과 동일하게 작동해야합니다 . 예를 들면 다음과 같습니다.

@login_manager.header_loader def load_user_from_header(header_val): header_val = header_val.replace('Basic ', '', 1) try: header_val = base64.b64decode(header_val) except TypeError: pass return User.query.filter_by(api_key=header_val).first()

기본적으로 Authorization헤더 값은 header_loader콜백으로 전달됩니다 . AUTH_HEADER_NAME구성에 사용 된 헤더를 변경할 수 있습니다 .

요청 로더를 사용한 사용자 정의 로그인 

때로는 헤더 값이나 쿼리 인수로 전달 된 API 키와 같은 쿠키를 사용하지 않고 사용자를 로그인하려고합니다. 이 경우 request_loader콜백을 사용해야합니다 . 이 콜백은 user_loaderuser_id 대신 플라스크 요청을 수락한다는 점을 제외하면 콜백 과 동일하게 작동해야합니다 .

예를 들어, Authorization헤더를 사용하여 URL 인수와 기본 인증 모두에서 로그인을 지원하려면 다음을 수행하십시오.

@login_manager.request_loader def load_user_from_request(request): # first, try to login using the api_key url arg api_key = request.args.get('api_key') if api_key: user = User.query.filter_by(api_key=api_key).first() if user: return user # next, try to login using Basic Auth api_key = request.headers.get('Authorization') if api_key: api_key = api_key.replace('Basic ', '', 1) try: api_key = base64.b64decode(api_key) except TypeError: pass user = User.query.filter_by(api_key=api_key).first() if user: return user # finally, return None if both methods did not login the user return None

익명 사용자 

기본적으로 사용자가 실제로 로그인하지 않은 current_user경우 AnonymousUserMixin객체 로 설정됩니다 . 다음과 같은 속성과 방법이 있습니다.

  • is_active하고 is_authenticated있습니다False
  • is_anonymous 이다 True
  • get_id() 보고 None

익명 사용자에 대한 사용자 정의 요구 사항이있는 경우 (예 : 권한 필드가 필요함) 익명 사용자를 작성하는 호출 가능 (클래스 또는 팩토리 기능)을 제공 할 수 있습니다 LoginManager.

login_manager.anonymous_user = MyAnonymousUser

나를 기억 

기본적으로 사용자가 브라우저를 닫으면 플라스크 세션이 삭제되고 사용자가 로그 아웃됩니다. "Remember Me"는 사용자가 브라우저를 닫을 때 실수로 로그 아웃되는 것을 방지합니다. 이것은 사용자가 로그 아웃 한 후 로그인 양식으로 사용자의 사용자 이름 또는 비밀번호를 기억하거나 미리 채우는 것을 의미 하지는 않습니다 .

“Remember Me”기능은 구현하기 까다로울 수 있습니다. 그러나, 플라스크 - 로그인은 거의 투명하게 - 그냥 통과 remember=True받는 login_user 전화. 쿠키는 사용자의 컴퓨터에 저장되며, Flask-Login은 해당 쿠키가 세션에없는 경우 해당 쿠키에서 자동으로 사용자 ID를 복원합니다. 쿠키가 만료되기까지의 시간은 REMEMBER_COOKIE_DURATION구성으로 설정하거나에 전달할 수 있습니다 login_user. 쿠키는 변조 방지 기능이므로 사용자가 쿠키를 변조 (예 : 다른 사람의 사용자 ID를 자신의 위치에 삽입)하는 경우 쿠키가 존재하지 않는 것처럼 쿠키가 거부됩니다.

이 수준의 기능은 자동으로 처리됩니다. 그러나 애플리케이션이 중요한 데이터를 처리하는 경우 추가 인프라를 제공하여 기억 쿠키의 보안을 강화할 수 있습니다.

대체 토큰 

사용자 토큰을 기억 토큰의 값으로 사용한다는 것은 로그인 세션을 무효화하기 위해 사용자의 ID를 변경해야한다는 것을 의미합니다. 이를 개선하는 한 가지 방법은 사용자 ID 대신 다른 사용자 ID를 사용하는 것입니다. 예를 들면 다음과 같습니다.

@login_manager.user_loader def load_user(user_id): return User.query.filter_by(alternative_id=user_id).first()

그런 다음 get_idUser 클래스  메소드는 사용자의 기본 ID 대신 대체 ID를 반환합니다.

def get_id(self): return unicode(self.alternative_id)

이렇게하면 사용자가 비밀번호를 변경할 때 사용자의 대체 ID를 임의로 생성 된 새 값으로 자유롭게 변경할 수 있으므로 이전 인증 세션이 유효하지 않게됩니다. 대체 ID는 여전히 사용자를 고유하게 식별해야합니다. 두 번째 사용자 ID로 생각하십시오.

새로운 로그인 

사용자가 로그인하면 해당 세션이 "새로 고침"으로 표시되어 실제로 해당 세션에서 인증되었음을 나타냅니다. 세션이 삭제되고 "기억하기"쿠키로 다시 로그인하면 "비 신규"로 표시됩니다. login_required신선도를 구분하지 않으므로 대부분의 페이지에 적합합니다. 그러나 개인 정보 변경과 같은 민감한 조치에는 새로 로그인해야합니다. (비밀번호 변경과 같은 작업은 항상 비밀번호를 다시 입력해야합니다.)

fresh_login_required, 사용자가 로그인했는지 확인하는 것 외에도 로그인이 최신인지 확인합니다. 그렇지 않은 경우 자격 증명을 다시 입력 할 수있는 페이지로 보냅니다. 당신은 사용자 정의 할 수와 같은 방법으로 동작을 사용자 정의 할 수 있습니다 login_required설정에 의해, LoginManager.refresh_view, needs_refresh_message, 그리고 needs_refresh_message_category:

login_manager.refresh_view = "accounts.reauthenticate" login_manager.needs_refresh_message = ( u"To protect your account, please reauthenticate to access this page." ) login_manager.needs_refresh_message_category = "info"

또는 새로 고침을 처리하기 위해 고유 한 콜백을 제공하여 :

@login_manager.needs_refresh_handler def refresh(): # do stuff return a_response

세션을 다시 최신으로 표시하려면 confirm_login함수를 호출하십시오 .

쿠키 설정 

쿠키의 세부 사항은 응용 프로그램 설정에서 사용자 지정할 수 있습니다.

REMEMBER_COOKIE_NAME "기억하기"정보를 저장할 쿠키의 이름입니다. 기본값 : remember_token
REMEMBER_COOKIE_DURATION 쿠키가 만료되기 전의 시간으로 datetime.timedelta개체 또는 정수 초입니다. 기본값 : 365 일 (도약 이외의 1 년)
REMEMBER_COOKIE_DOMAIN "Remember Me"쿠키가 도메인을 교차해야하는 경우 여기에 도메인 값을 설정하십시오 (예 :의 .example.com 모든 하위 도메인에서 쿠키를 사용하도록 허용 example.com). 기본: None
REMEMBER_COOKIE_PATH “Remember Me”쿠키를 특정 경로로 제한합니다. 기본: /
REMEMBER_COOKIE_SECURE "Remember Me"쿠키의 범위를 보안 채널 (일반적으로 HTTPS)로 제한합니다. 기본: None
REMEMBER_COOKIE_HTTPONLY 클라이언트 측 스크립트가 "Remember Me"쿠키에 액세스하지 못하게합니다. 기본: False
REMEMBER_COOKIE_REFRESH_EACH_REQUEST True쿠키로 설정하면 요청마다 새로 고쳐 지므로 수명이 단축됩니다. 플라스크처럼 작동합니다 SESSION_REFRESH_EACH_REQUEST. 기본: False

세션 보호 

위의 기능은 쿠키 도둑으로부터“Remember Me”토큰을 보호하는 데 도움이되지만 세션 쿠키는 여전히 취약합니다. Flask-Login에는 세션 보호 기능이있어 사용자의 세션 도난을 방지 할 수 있습니다.

LoginManager및 앱 구성에서 세션 보호를 구성 할 수 있습니다 . 활성화 된 경우 basic또는 strong 모드 에서 작동 할 수 있습니다 . 상의를 설정하려면 LoginManager, 설정된 session_protection속성을하는 "basic" "strong":

login_manager.session_protection = "strong"

또는 비활성화하려면 :

login_manager.session_protection = None

기본적으로 "basic"모드 에서 활성화 됩니다. 그것은 설정하여 응용 프로그램의 설정에서 비활성화 할 수 있습니다 SESSION_PROTECTION에 대한 설정을 None, "basic"또는 "strong".

세션 보호가 활성화되면 각 요청마다 사용자 컴퓨터의 식별자 (기본적으로 IP 주소 및 사용자 에이전트의 보안 해시)가 생성됩니다. 세션에 연관된 식별자가 없으면 생성 된 식별자가 저장됩니다. 식별자가 있고 생성 된 식별자와 일치하면 요청이 정상입니다.

식별자가 basic모드에서 일치하지 않거나 세션이 영구적 일 경우 세션은 단순히 새로 고침되지 않은 것으로 표시되며 새로 로그인해야하는 모든 것 때문에 사용자가 다시 인증해야합니다. (물론, 유효한 경우 새 로그인을 사용하고 있어야합니다.)

strong비 영구 세션의 모드 에서 식별자가 일치하지 않으면 전체 세션 (및 기억 토큰이있는 경우)이 삭제됩니다.

API에 대한 세션 쿠키를 사용하지 않도록 설정 

API 인증시 Flask Session 쿠키 설정을 비활성화 할 수 있습니다. 이렇게하려면 요청에 설정 한 플래그에 따라 세션 저장을 건너 뛰는 사용자 정의 세션 인터페이스를 사용하십시오. 예를 들면 다음과 같습니다.

from flask import g from flask.sessions import SecureCookieSessionInterface from flask_login import user_loaded_from_header class CustomSessionInterface(SecureCookieSessionInterface): """Prevent creating session from API requests.""" def save_session(self, *args, **kwargs): if g.get('login_via_header'): return return super(CustomSessionInterface, self).save_session(*args, **kwargs) app.session_interface = CustomSessionInterface() @user_loaded_from_header.connect def user_loaded_from_header(self, user=None): g.login_via_header = True

이렇게하면 사용자가를 사용하여 인증 할 때마다 플라스크 세션 쿠키를 설정할 수 없습니다 header_loader.

현지화 

기본적 으로 사용자가 로그인해야 할 때 메시지를 표시 하는 LoginManager데 사용 flash됩니다.이 메시지는 영어로되어 있습니다. 당신은 현지화를 필요로하는 경우, 설정 localize_callback의 속성 LoginManager들이 전송되기 전에 이러한 메시지 호출 할 수있는 기능을 flash예를 들어, gettext. 이 함수는 메시지와 함께 호출되고 flash대신 반환 값이 전송 됩니다.

API 문서 

이 문서는 Flask-Login의 소스 코드에서 자동으로 생성됩니다.

로그인 설정하기 

클래스 flask_login.LoginManager( app = None , add_context_processor = True )[출처]

이 개체의 로깅에 사용되는 설정을 누릅니다.의 인스턴스를 사용 LoginManager하는 하지 그것을 공장 기능의 앱에 바인드 다음 코드의 본체에서 하나를 만들 수 있도록, 특정 애플리케이션에 바인딩을합니다.

setup_app( app , add_context_processor = True )[출처]

이 메소드는 더 이상 사용되지 않습니다. LoginManager.init_app()대신 사용하십시오 .

unauthorized( )[출처]

사용자가 로그인해야 할 때 호출됩니다.에 콜백을 등록하면 호출됩니다 LoginManager.unauthorized_handler(). 그렇지 않으면 다음 조치를 수행합니다.

  • LoginManager.login_message사용자에게 플래시 .
  • 앱이 블루 프린트를 사용하는 경우을 사용하여 현재 블루 프린트의 로그인보기를 찾으십시오 blueprint_login_views. 앱이 블루 프린트를 사용하지 않거나 현재 블루 프린트에 대한 로그인보기가 지정되지 않은 경우의 값을 사용하십시오 login_view.
  • 사용자를 로그인보기로 리디렉션하십시오. 액세스하려는 페이지는 next쿼리 문자열 변수 로 전달 되므로 홈페이지 대신 존재하는 경우 리디렉션 할 수 있습니다. 또는 nextUSE_SESSION_FOR_NEXT가 설정된 것처럼 세션에 추가됩니다 .

LoginManager.login_view정의되지 않은 경우 HTTP 401 (무단) 오류가 대신 발생합니다.

이것은 뷰 또는 before / after_request 함수에서 리턴되어야하며, 그렇지 않으면 경로 재 지정이 적용되지 않습니다.

needs_refresh( )[출처]

사용자가 로그인 할 때 호출되지만 세션이 오래되었으므로 다시 인증해야합니다. 에 콜백을 등록하면 호출됩니다 needs_refresh_handler. 그렇지 않으면 다음 조치를 수행합니다.

  • LoginManager.needs_refresh_message사용자에게 플래시 .
  • 사용자를로 리디렉션하십시오 LoginManager.refresh_view. 액세스하려는 페이지는 next 쿼리 문자열 변수 로 전달 되므로 홈페이지 대신 존재하는 경우 리디렉션 할 수 있습니다.

LoginManager.refresh_view정의되지 않은 경우 HTTP 401 (무단) 오류가 대신 발생합니다.

이것은 뷰 또는 before / after_request 함수에서 리턴되어야하며, 그렇지 않으면 경로 재 지정이 적용되지 않습니다.

일반 구성

user_loader( 콜백 )[출처]

세션에서 사용자를 다시로드하기위한 콜백을 설정합니다. 설정 한 함수는 사용자 ID (a unicode)를 가져 와서 사용자 개체를 반환하거나 None사용자가 존재하지 않는 경우 반환해야 합니다.

매개 변수 :

콜백 ( callable ) – 사용자 객체를 검색하기위한 콜백입니다.

header_loader( 콜백 )[출처]

이 기능은 더 이상 사용되지 않습니다. LoginManager.request_loader()대신 사용하십시오 .

헤더 값에서 사용자를로드하기위한 콜백을 설정합니다. 설정 한 함수는 인증 토큰을 가져 와서 사용자 개체를 반환하거나 None사용자가없는 경우 반환해야 합니다.

매개 변수 :

콜백 ( callable ) – 사용자 객체를 검색하기위한 콜백입니다.

anonymous_user

익명 사용자를 생성하는 클래스 또는 팩토리 함수로, 아무도 로그인하지 않은 경우에 사용됩니다.

unauthorized 구성

login_view

사용자가 로그인해야 할 때 리디렉션 할보기의 이름입니다. (인증 기관이 응용 프로그램 외부에있는 경우에도 절대 URL 일 수 있습니다.)

login_message

사용자가 로그인 페이지로 리디렉션 될 때 깜박이는 메시지입니다.

unauthorized_handler( 콜백 )[출처]

이것에 의해 unauthorized메소드 가 사용하는 콜백이 설정 됩니다 login_required. 인수를 취하지 않으며 일반보기 대신 사용자에게 보낼 응답을 리턴해야합니다.

매개 변수 :

콜백 ( callable ) – 인증되지 않은 사용자의 콜백입니다.

needs_refresh 구성

refresh_view

사용자를 다시 인증해야 할 때 리디렉션 할보기의 이름입니다.

needs_refresh_message

사용자가 재 인증 페이지로 리디렉션 될 때 깜박이는 메시지입니다.

needs_refresh_handler( 콜백 )[출처]

이것에 의해 needs_refresh메소드 가 사용하는 콜백이 설정 됩니다 fresh_login_required. 인수를 취하지 않으며 일반보기 대신 사용자에게 보낼 응답을 리턴해야합니다.

매개 변수 :

콜백 ( callable ) – 인증되지 않은 사용자의 콜백입니다.

로그인 메커니즘 

flask_login.current_user

현재 사용자의 프록시

flask_login.login_fresh( )[출처]

True현재 로그인이 최신인지를 반환 합니다.

flask_login.login_user( user , remember = False , duration = None , force = False , fresh = True )[출처]

사용자를 로그인합니다. 실제 사용자 개체를 여기에 전달해야합니다. 사용자 is_active속성이 False인 경우 forceis가 아닌 한 로그인하지 않습니다 True.

이것은 True로그인 시도가 성공 False하고 실패한 경우 (즉, 사용자가 비활성화되어 있기 때문에) 리턴 합니다 .

매개 변수 :

  • user ( object ) – 로그인 할 사용자 개체입니다.
  • remember ( bool ) – 세션이 만료 된 후 사용자를 기억할지 여부입니다. 기본값은 False입니다.
  • duration ( datetime.timedelta) – 기억 쿠키가 만료되기 전의 시간입니다. 경우 None설정의 값 세트가 사용됩니다. 기본값은 None입니다.
  • force ( bool ) – 사용자가 비활성 인 경우,이를 설정하여 사용자가 True로그인하지 않게합니다. 기본값은 False입니다.
  • fresh ( bool ) – False"fresh"가 아닌 것으로 표시된 세션으로 사용자를 로그인 하도록 설정합니다 . 기본값은 True입니다.

flask_login.logout_user( )[출처]

사용자를 로그 아웃합니다. (실제 사용자를 전달할 필요는 없습니다.) 또한 Remember me 쿠키가있는 경우이를 정리합니다.

flask_login.confirm_login( )[출처]

현재 세션을 최신으로 설정합니다. 쿠키에서 세션을 다시로드하면 세션이 오래됩니다.

뷰 보호 

flask_login.login_required( 펑크 )[출처]

이를 사용하여보기를 장식하면 실제보기를 호출하기 전에 현재 사용자가 로그인 및 인증되었는지 확인합니다. 그렇지 않은 경우 LoginManager.unauthorized콜백을 호출합니다 . 예를 들면 다음과 같습니다.

@app.route('/post') @login_required def post(): pass

사용자가 로그인해야하는 특정 시간 만 필요한 경우 다음을 수행하면됩니다.

if not current_user.is_authenticated: return current_app.login_manager.unauthorized()

...이 함수는 뷰에 추가하는 코드입니다.

단위 테스트시 인증을 전체적으로 끄는 것이 편리 할 수 ​​있습니다. 이를 활성화하기 위해 애플리케이션 구성 변수 LOGIN_DISABLED 가로 설정된 True경우이 데코레이터는 무시됩니다.

노트

 CORS에 대한 W3 지침 요청을 프리 플라이트 , HTTP를 OPTIONS요청 로그인 검사에서 제외됩니다.

매개 변수 :

func ( function ) – 장식 할 뷰 함수입니다.

flask_login.fresh_login_required( 펑크 )[출처]

이를 사용하여보기를 장식하면 현재 사용자의 로그인이 최신 상태인지 확인합니다. 즉, 세션이 '기억하기'쿠키에서 복원되지 않았습니다. 쿠키 도둑의 노력을 방해하기 위해 비밀번호 나 이메일 변경과 같은 민감한 작업을 보호해야합니다.

사용자가 인증되지 않은 경우 LoginManager.unauthorized()정상으로 호출됩니다. 인증되었지만 세션이 최신 상태가 아닌 경우 LoginManager.needs_refresh()대신 호출 됩니다. (이 경우을 제공해야합니다 LoginManager.refresh_view.)

구성 login_required()변수와 관련 하여 데코레이터와 동일하게 작동합니다 .

노트

 CORS에 대한 W3 지침 요청을 프리 플라이트 , HTTP를 OPTIONS요청 로그인 검사에서 제외됩니다.

매개 변수 :

func ( function ) – 장식 할 뷰 함수입니다.

사용자 개체 도우미 

수업 flask_login.UserMixin[출처]

이것은 Flask-Login이 사용자 객체가 가질 것으로 기대하는 메소드에 대한 기본 구현을 제공합니다.

수업 flask_login.AnonymousUserMixin[출처]

익명 사용자를 나타내는 기본 개체입니다.

유틸리티 

flask_login.login_url( login_view , next_url = 없음 , next_field = 'next' )[출처]

로그인 페이지로 리디렉션하기위한 URL을 만듭니다. login_view제공되는 경우 URL 만 반환합니다. next_url그러나 제공되는 경우 next=URL로그인보기가 해당 URL로 다시 리디렉션 될 수 있도록 쿼리 문자열에 매개 변수 가 추가 됩니다. Flask-Login의 기본 무단 핸들러는 로그인 URL로 리디렉션 할 때이 기능을 사용합니다. 사용 된 호스트 이름을 강제하려면 호스트로 설정하십시오 FORCE_HOST_FOR_REDIRECTS. 요청 헤더 Host 또는 X-Forwarded-For가있는 경우 외부 사이트로 리디렉션되지 않습니다.

매개 변수 :

  • login_view ( str ) – 로그인보기의 이름입니다. 또는 로그인보기의 실제 URL입니다.
  • next_url ( str ) – 리디렉션을위한 로그인보기를 제공 할 URL입니다.
  • next_field ( str ) – 다음 URL을 저장할 필드입니다. 기본값은 next입니다.

신호 

코드에서 이러한 신호를 사용하는 방법에 대한 정보 는 신호에 대한 Flask 설명서를 참조하십시오 .

flask_login.user_logged_in

사용자가 로그인하면 전송됩니다. 발신자 인 앱 외에도 앱이 전달됩니다 user(이는 로그인 한 사용자 임).

flask_login.user_logged_out

사용자가 로그 아웃 할 때 전송됩니다. 발신자 인 앱 외에도 앱이 전달 user되어 로그 아웃중인 사용자입니다.

flask_login.user_login_confirmed

사용자의 로그인이 확인되면 새 것으로 표시됩니다. (일반 로그인을 위해 호출되지는 않습니다.) 앱 외에 추가 인수를받지 않습니다.

flask_login.user_unauthorized

에서 unauthorized메소드가 호출 될 때 전송됩니다 LoginManager. 앱 외에 추가 인수를받지 않습니다.

flask_login.user_needs_refresh

에서 needs_refresh메소드가 호출 될 때 전송됩니다 LoginManager. 앱 외에 추가 인수를받지 않습니다.

flask_login.session_protected

세션 보호가 적용될 때마다 전송되며 세션이 새로 고침되지 않거나 삭제 된 것으로 표시됩니다. 앱 외에 추가 인수를받지 않습니다.

+ Recent posts