반응형
반응형

SSO(Single Sign-On) 구현을 위한 토큰(Token)의 활용

 


ID/PW 로그인
AccessToken / RefreshToken 생성
AccessToken 소멸하면 RefreshToken으로 인증서버에 AccessToken 재요청
RefreshToken 소멸시 재로그인
 * JWT(JSON Web Token)
 * Token은 Base64 Encoding으로 한다. 토큰에 서명(signiture)부분을 추가해서 서명에 비밀키를 사용. 

 

====================================================================

 

SSO(Single Sign-On)는 무엇인가?

SSO(Single Sign-On)은 한 번의(Single) 로그인 인증(Sign-On)으로 여러 개의 서비스를 추가적인 인증 없이 사용할 수 있는 기술이다. 인증은 하나의 시스템(인증 서버)에서 수행하고, 그 인증 서버가 서비스를 각각 담당하는 서버에 인증 정보를 알려주는 방식이다.




주로 다양한 서비스를 유사한 도메인 혹은 동일한 탑 레벨 도메인(TLD:Top Level Domain)을 서비스하는 엔터프라이즈 서비스 제공자들이 사용자에게 간편한 로그인을 제공하기 위해 사용한다.

예를 들면, 이런 흐름이다.
① www.samsung.com에서 로그인을 하면, 인증 서버 account.samsung.com으로 이동한다.
② account.samsung.com에서 로그인을 성공하면 다시 www.samsung.com으로 돌아온다.
③ 삼성의 다른 서비스에 접속하면, 별도의 추가 로그인 없이 이미 로그인된 상태로 서비스를 즐긴다.

같은 맥락으로 Gmail에 Google 계정으로 로그인을 하면, YouTube나 Google Drive는 별도 로그인 없이 Gmail 로그인에 사용한 구글 계정을 동일하게 사용하는 것도 SSO 기술이다.

SSO를 구현하기 위한 기술 요소는?

SSO를 구현하려 한다면 인증 서버를 준비하고, 이를 다양한 서비스들과 어떻게 인증 관련으로 연계할지 설계해야 한다. 인증 서버에서 인증을 성공적으로 마쳤다는 '증거'를 다른 서비스들이 어떻게 믿게 만들 것인지에 대한 기술적 고민도 필요하다.

기업 내 솔루션에서 SSO는 전통적으로는 모든 사용자(직원)의 인증 정보를 담고 있는 AD(Active Directory)이나 LDAP(Lightweight Directory Access Protocol)을 적용한 솔루션들을 많이 사용해왔다.

SSO의 직접적인 구현을 위해서 여러 가지 방법이 있겠지만 이 글은 인증 토큰(authentication token)을 사용한 SSO 방식에 대한 글이다. 여기서 토큰이란, 최초 인증이 성공한 사용자에게 일종의 증표로 인증 서버가 발급하는 정보다.

예전의 웹 개발에서는 로그인에 성공한 사용자는 웹 서버와 Session을 맺고, SessionID 정보를 쿠키로 받아, 그 쿠키를 로그인의 증표로 사용하였다. 모든 요청 헤더에 SessionID 쿠키를 넣고 웹 서버에 접속을 하면, 웹 서버는 서버에 보관한 Session 정보와 비교하여 유효하게 로그인한 사용자임을 확인하고 콘텐츠를 제공하는 방식이었다. 매번 요청마다 서버가 Session 정보를 확인해야 하는 부담, 서버가 Session 정보를 어디엔가(DB 혹은 Redis) 저장해야 하는 번거로움과 복잡한 구현 방식이 단점이라 할 수 있다.

이에 반해 토큰 방식은 Session 방식과 다르게 서버가 각각 로그인한 사용자의 세션 정보를 따로 보관하지 않는다. 한번 인증 토큰이 클라이언트에게 발급하면, 클라이언트는 추후 요청부터는 그 토큰을 포함하고, 서버는 클라이언트 요청에 포함된 토큰을 그때그때 확인할 뿐이다. 현재 Facebook, YouTube를 비롯한 소셜미디어, 포탈, 이커머스 서비스처럼 가입자 기반의 로그인 인증이 필요한 서비스들이 토큰 인증 방식을 많이 사용하고 있다.

초기에는 SSO가 저변화되면서 많은 서비스들이 SSO 상용 서비스에서 제공하는 SAML(Security Assertion Markup Language) 방식을 사용하였다. SAML은 XML 형태의 마크업으로, 간단한 정보 전달을 위해 많은 태그가 사용되는 비효율성이 있다. 그 이후부터는 SSO에서도 토큰을 사용하고 있다.


토큰을 사용한 SSO 서비스 다이어그램 

SSO에서 세션과 토큰을 어떻게 사용하는지 아래 다이어그램으로 이해해보자.



① 사용자는 Service1에 접속하여 로그인 버튼을 클릭한다.
② Service1은 인증 서비스(idP: Identity provider)로 해당 요청을 Redirect 한다.
③ 인증 서비스는 사용자에게 로그인 화면을 제공한다.
④ 사용자는 ID/PW (혹은 OAUTH2.0)을 입력한다.
⑤ 인증 서비스는 회원 DB와 비교하여 ID/PW가 올바르면 인증 토큰을 발급하며 Service1으로 돌려보낸다.
⑥ Service1은 발급된 토큰을 확인하고, 올바른 토큰이라면 사용자의 로그인 처리를 해준다.
⑦ 사용자는 Service2에 접속한다.
⑧ Service2는 이 사용자의 세션이 아직 유효한지 확인하고 유효하다면, Service2 용도의 토큰을 발급한다.
⑨ Service1은 발급된 토큰을 확인하고, 올바른 토큰이라면 사용자의 로그인 처리를 해준다.


여전히 세션이 필요한 이유는 한번 발급된 토큰만 믿을 수없기도 하고, 일반적으로 토큰은 짧은 유효 시간을 갖는데 비해, 서버에는 세션 정보를 오랫동안 보관하고 그 기간 내에 재접속한 사용자를 지원할 수 있기 때문이다.


유효 시간이 만료된 토큰 사용자가 다시 로그인하는 것은 불편하니, 다음과 같은 방법을 사용한다.

- 인증 서버는 ID/PW를 DB에서 확인하고, 정상 로그인이면 AccessToken과 RefreshToken을 발행한다.
- AccessToken은 exp가 짧다. 만료되면 RefreshToken으로 인증 서버에게 AccessToken를 재요청한다.
- RefreshToken은 exp가 상대적으로 길고, 인증 서버의 세션 정보를 포함한다.
- AccessToken 재요청을 받은 인증 서버는 RefreshToken과 세션 정보를 비교 후 재발급해준다.
- RefreshToken 마저 유효 시간이 지나면, 사용자는 다시 ID/PW 로그인을 해야 한다.

한번 로그인했던 Facebook이나 YouTube의 로그인이 상당 기간 필요 없는 것은 위의 방법을 사용하기 때문이다. 브라우저의 쿠키와 temporary internet folder를 삭제하면 모든 토큰은 삭제된다. 때에 따라 AccessToken을 cookie에 저장하고, cookie는 브라우저가 닫히면 삭제되도록 설정할 수도 있다.


토큰에는 어떤 정보가 있고 어떻게 확인하나?

여기에서의 핵심은 토큰이 어떤 정보를 가지고 있고, 각 Service1과 Service2가 유효한 토큰임을 어떻게 확인할 것인지에 대한 디자인이다. 토큰의 종류는 여러 가지이지만 예제에선 JWT(JSON Web Token)을 사용하였다.



① 인증 서버(idP)와 각 Service 서버들은 사전에 비밀키(private key)를 공유한다.
② ID/PW로 정상적인 인증이 확인되면, 인증 서버는 토큰에 이메일, 이름, 유효 시간 등을 입력하여 발급한다.
③ 토큰을 Base64 Encoding 한다. 암호화가 아닌 인코딩이기 때문에 내용은 누구나 알 수 있다.
④ 토큰에 서명(signature) 부분을 추가하여 위 변조를 방지한다. 서명에 비밀키를 사용한다.
⑤ HTTPS 보안 채널로 토큰 확인을 요청한다. 토큰이 유실되더라도 비밀키가 없는 해커는 내용을 변조할 수 없다.
⑥ Service 서버는 비밀키로 토큰 변조 여부를 확인하고, email 등의 사용자 정보 확인 후, 인증 처리를 해준다.

이 방식의 장점은 가벼운 토큰을 사용하여 인증 처리 작업을 하는 서비스들이 부담을 갖지 않는 구조이고, 비밀키 없이는 토큰을 변조하지 못한다는 보안성이다.

단점은 아무리 HTTPS로 토큰을 보낸다고 하더라도, 중간자 공격 등으로 토큰을 훔친 해커는 토큰을 변조하지 않고 그대로 사용한다면, 로그인한 사용자와 동일하게 보일 수 있다는 보안 취약점이다. 그래서 User-Agent 혹은 IP 주소를 확인한다거나, 추가적인 여러 가지 보완책을 마련해야 한다. Naver 서비스의 경우, AccessToken이 유효하더라도 사용자의 IP 주소가 바뀌면 다시 로그인을 하도록 하는 것도 이런 이유 때문이다.


SSO(Single Sign-On) 구현을 위한 토큰(Token)의 활용 : https://brunch.co.kr/@sangjinkang/36

반응형
반응형

os.getcwd()

import os

#작업하는 경로(위치)가 어디인지 확인
print(os.getcwd())

#절대경로
with open("D:/python/res/path_test/test.txt", "r", encoding="utf-8") as f:
    data = f.read()
    print(data)

#상대경로
with open("path_test/test.txt", "r", encoding="utf-8") as f:
    data = f.read()
    print(data)

cwd = current working directory  현재 작업 중인 디렉터리(폴더)를 의미하고, 

get = 얻어온다는 의미가 있으니, 현재 작업 중인 폴더를 얻어온다는 의미가 되겠습니다.

반응형
반응형

 

pip install pandas 

 

conda install -c anaconda pandas 

When working with tabular data, such as data stored in spreadsheets or databases, pandas is the right tool for you. pandas will help you to explore, clean, and process your data. In pandas, a data table is called a DataFrame.

반응형
반응형

  현재 년, 월, 일, 시, 분, 초 문자열로 표현하기 (yyyymmddhh24miss 형태) 

## 시간 표시  ##################################### 
import time
import datetime
now = datetime.datetime.now()
nowStr = "{:%Y%m%d%H%M%S}".format(now)
timeserise = time.time()
timeserise = str(int(timeserise))
#print(timeserise)
print(now)
print(" 년월일시분초 :" + nowStr)

#################################################
반응형
반응형

NLTK 에러시 - Resource punkt not found 일때 

아래 다운로드 추가하면 됩니다. 

 

import nltk
nltk.download()

import os
from konlpy.tag import Okt

import nltk
nltk.download()

from nltk import word_tokenize, pos_tag, ne_chunk 
sentence = 'Mike is working at IT Centre' 

# 토큰화, 품사태깅 pos_tag 후 -> ne_chunk 개체명인식 
sentence = pos_tag(word_tokenize(sentence)) 
print(sentence) 

# 개체명 인식 
sentence = ne_chunk(sentence) 
print(sentence)

반응형
반응형

NLTK 설치

저는 아나콘다 환경에서 파이썬을 사용하고 있으므로 이미 루트 가상환경에 NLTK가 설치가 되어있었습니다. KoNLPy와 다르게 별도의 설정등을 해줄 필요가 없습니다.아나콘다 내에서 가상환경을 따로 만들어 설치를 해줄시엔 해당 가상환경 activate 후에

> conda install nltk]
> conda update nltk

위 명령어를 입력하여 설치해주면 됩니다.

 

하지만 예제를 수행하면 여러 에러 메세지들을 볼 수 있습니다. 예를들어 nltk.download('words'), nltk.download('maxent_ne_chunker')를 하라는 등의 메세지가 뜨면 오류메세지에 뜬 명령어 그대로 입력해서 별도의 모듈들을 설치해주면 됩니다.

 

 

○ 예제 시행해보기

from nltk import word_tokenize, pos_tag, ne_chunk

sentence = 'Mike is working at IT Centre'

# 토큰화, 품사태깅 pos_tag 후 -> ne_chunk 개체명인식
sentence = pos_tag(word_tokenize(sentence))
print(sentence)

# 개체명 인식
sentence = ne_chunk(sentence)
print(sentence)

 

결과

# [('Mike', 'NNP'), ('is', 'VBZ'), ('working', 'VBG'), 
# ('at', 'IN'), ('IT', 'NNP'), ('Centre', 'NNP')]
# (S
#   (GPE Mike/NNP)
#   is/VBZ
#   working/VBG
#   at/IN
#   (ORGANIZATION IT/NNP Centre/NNP))

 

 

 

 

 

○ 몇 가지 기능 살펴보기

 

1. nltk.Text()

 

nltk.Text()는 자연어 데이터의 탐색을 편리하게 해주는 다양한 기능들을 제공합니다.

import nltk
from nltk.corpus import gutenberg
from nltk import regexp_tokenize

f = gutenberg.fileids()
doc_en = gutenberg.open('austen-emma.txt').read()

pattern = r'''(?x) ([A-Z]\.)+ | \w+(-\w+)* | \$?\d+(\.\d+)?%? | \.\.\. | [][.,;"'?():-_`]'''
tokens_en = regexp_tokenize(doc_en, pattern)

en = nltk.Text(toekns_en)

 

테스트를 하기 위해 NLTK에서 제공하는 제인오스틴의 소설 Emma데이터를 다운받습니다. 이후 문서를 토큰으로 나누는 작업을 해주었는데 한국어를 토크나이즈하거나 품사태깅, 개체명 태깅 등을 할 때는 KoNLPy를 이용하는 것이 훨씬 낫다고 봅니다.


예를 들어 NLTK에서 '나는 바보다'라는 문장에서 '바보다'라는 토큰의 개체명을 'Organization'으로 인식하는 등의 문제가 있습니다. 그래서 한국어 처리를 할 때에는 nltk를 데이터를 탐색하는 용도로 많이 사용하는 듯 합니다.

 

 

2. 그래프 그리기

 

en.plot(50) 

en문서의 50개의 토큰만 플롯으로 그려보았습니다.

 


en.dispersion_plot(['Emma','Frank','Jane'])

 


 

 

 

 

 

 

 

3. 문서 탐색

 

print(len(en.tokens)) # 토큰의 개수 확인
print(len(set(en.tokens))) # Unique 토큰의 개수 확인
en.vocab() # Frequency Distribution 확인
print(en.count('Emma')) # 'Emma'의 개수
en.concordance('Emma', lines=5) # 'Emma'가 들어있는 5개의 문장만 출력
en.similar('Emma')
en.similar('Frank') # 비슷한 단어 찾기
> 결과

> 191061
> 7927
> FreqDist({',': 12018, '.': 8853, 'to': 5127, 'the': 4844, 'and': 4653, 'of': 4278, '"': 4187, 'I': 3177, 'a': 3000, 'was': 2385, ...})
> 865
> Displaying 5 of 865 matches:
                                     Emma by Jane Austen 1816 ] VOLUME I CHAPT
                                     Emma Woodhouse , handsome , clever , and
both daughters , but particularly of Emma . Between them it was more the int
 friend very mutually attached , and Emma doing just what she liked ; highly e
r own . The real evils , indeed , of Emma situation were the power of havi
> she it he i harriet you her jane him that me and all they them there herself was hartfield be
mr mrs emma harriet you it her she he him hartfield them jane that isabella all herself look i me

 

그래프를 그리는 것 외에도 토큰의 개수나 frequency distribution등을 확인하여 데이터의 구조를 살펴보는데 좋은 기능들도 많이 제공하고 있습니다.

 

 


4. Chunking nltk.RegexParser()

 

Chunking 얕은 구문 분석, 음성 및 단구 (명사구와 같은)를 식별하는 것

tokens = "The little yellow dog barked at the Persian cat".split()
tags_en = nltk.pos_tag(tokens)

parser_en = nltk.RegexpParser("NP: {<DT>?<JJ>?<NN.*>*}")
chunks_en = parser_en.parse(tags_en)
chunks_en.draw()
결과

[('The', 'DT'),
 ('little', 'JJ'),
 ('yellow', 'NN'),
 ('dog', 'NN'),
 ('barked', 'VBD'),
 ('at', 'IN'),
 ('the', 'DT'),
 ('Persian', 'NNP'),
 ('cat', 'NN')]

 

 


5. 워드클라우드 그리기

 

import nltk
ko = nltk.Text(tokens_ko, name='대한민국 국회 의안 제 1809890호')

 한국어 예제를 하나 불러옵니다.

 

# 예제의 빈도분포(frequency distribution) 살펴보기

print(ko.vocab())
type(ko.vocab()) # 데이터타입, 속성목록 확인
dir(ko.vocab()) # 예제문서의 단어사전 살펴보기

data = ko.vocab().items()
print(data)
print(type(data)) # items()를 이용하면 빈도분포의 item 전체를 set형태로 확인 가능합니다.
> 결과

> FreqDist({'.': 61, '의': 46, '육아휴직': 38, '을': 34, '(': 27, ',': 26, '이': 26, ')': 26, '에': 24, '자': 24, ...})
> nltk.probability.FreqDist
> ['B',
 'N',
 ...
 'items',
 ...
 'pop',
 'popitem',
 'pprint',
 'r_Nr',
 'setdefault',
 'subtract',
 'tabulate',
 'unicode_repr',
 'update',
 'values']
 
 > dict_items([('명', 5), ('예상된', 3), ('하나', 1), ('11', 2), ('팀', 2), ...])
<class 'dict_items'>

데이터 탐색@@

 

import csv
with open('words.csv', 'w', encoding='utf-8') as f:
    f.write('word,freq\n')
    writer = csv.writer(f)
    writer.writerows(data)

탐색한 데이터 set을 words.csv라는 파일에 저장하여 워드클라우드를 그리는데 이용하도록 하겠습니다.

 

<!DOCTYPE html>
<html>
<head>
  <style>
    text:hover {
        stroke: black;
    }
  </style>
  <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
  <script src="d3.layout.cloud.js"></script>
</head>
<body>
  <div id="cloud"></div>
  <script type="text/javascript">
    var weight = 3,   // change me
        width = 960,
        height = 500;

    var fill = d3.scale.category20();
    d3.csv("words.csv", function(d) {
        return {
          text: d.word,
          size: +d.freq*weight
        }
      },
      function(data) {
        d3.layout.cloud().size([width, height]).words(data)
          //.rotate(function() { return ~~(Math.random() * 2) * 90; })
          .rotate(0)
          .font("Impact")
          .fontSize(function(d) { return d.size; })
          .on("end", draw)
          .start();

        function draw(words) {
          d3.select("#cloud").append("svg")
              .attr("width", width)
              .attr("height", height)
            .append("g")
              .attr("transform", "translate(" + width/2 + "," + height/2 + ")")
            .selectAll("text")
              .data(words)
            .enter().append("text")
              .style("font-size", function(d) { return d.size + "px"; })
              .style("font-family", "Impact")
              .style("fill", function(d, i) { return fill(i); })
              .attr("text-anchor", "middle")
              .attr("transform", function(d) {
                return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
              })
            .text(function(d) { return d.text; });
        }
      });
  </script>
</body>
</html>

위 코드를 index.html로 저장하고 words.csv가 있는 폴더내에 저장합니다.

 

python -m http.server 8888 

그리고 프롬프트웨 위 명령어를 입력하여 실행시켜준 뒤, http://localhost:8888로 접속하면,

 

생성된 워드클라우드를 확인할 수 있습니다.



출처: https://ebbnflow.tistory.com/147 [Dev Log : 삶은 확률의 구름]

반응형

+ Recent posts