Skip to content

Commit f5ab64e

Browse files
committed
Authorization, Password 암호화
1 parent fef3e91 commit f5ab64e

8 files changed

Lines changed: 108 additions & 20 deletions

File tree

Pipfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ flask-marshmallow = "*"
1717
flask-migrate = "*"
1818
pymysql = "*"
1919
flask-restplus = "*"
20+
pyjwt = "*"
2021

2122
[requires]
2223
python_version = "3.7"

Pipfile.lock

Lines changed: 12 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/api/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
from flask_restplus import Api
66
from app.users.views import API as users_api
77
from app.posts.views import API as posts_api
8+
from app.api.auth_type import ACCESS_TOKEN, BASIC_AUTH
89

9-
REST_API = Api()
10+
REST_API = Api(authorizations={**ACCESS_TOKEN, **BASIC_AUTH})
1011

1112
REST_API.add_namespace(users_api, '/user')
1213
REST_API.add_namespace(posts_api, '/post')

app/api/auth_type.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import jwt
2+
from flask import request, Response
3+
from functools import wraps
4+
5+
SECERET_KEY = "Secret Hellow"
6+
ACCESS_TOKEN = {
7+
'Access Token': {
8+
'type': 'apiKey',
9+
'in': 'header',
10+
'name': 'Authorization'
11+
}
12+
}
13+
BASIC_AUTH = {
14+
'Basic Auth': {
15+
'type': 'basic',
16+
'in': 'header',
17+
'name': 'Authorization'
18+
},
19+
}
20+
21+
def confirm_token(f):
22+
@wraps(f)
23+
def decorated_function(*args, **kwargs):
24+
access_token = request.headers['Authorization']
25+
if access_token is not None:
26+
try:
27+
payload = jwt.decode(access_token, SECERET_KEY, "HS256")
28+
except jwt.InvalidTokenError:
29+
payload = None
30+
if payload is None:
31+
return Response(status=401)
32+
user_id = payload["user_id"]
33+
# 원하는 작업
34+
else:
35+
return Response(status=401)
36+
37+
return f(*args, **kwargs)
38+
return decorated_function

app/posts/views.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from app.posts.models import Posts, PostsSchema
1010
from app.users.models import Users, UsersSchema
1111
from app.api.database import DB
12+
from app.api.auth_type import confirm_token, ACCESS_TOKEN, BASIC_AUTH
1213

1314
API = Namespace('Posts', description="Post's REST API")
1415
POSTS_SCHEMA = PostsSchema()
@@ -41,14 +42,17 @@ def get(self):
4142
return make_response(body, code.value)
4243

4344
@API.expect(post_field)
44-
@API.doc('post')
45+
@confirm_token
46+
@API.doc('post', security=ACCESS_TOKEN)
4547
def post(self):
4648
args_ = self.parser.parse_args()
4749
post = Posts(author_id=args_['author_id'], title=args_['title'], body=args_['body'])
4850
return post.add(post, POSTS_SCHEMA)
4951

5052
@API.route('/<int:reqno>')
5153
class PostItem(Resource):
54+
@confirm_token
55+
@API.doc('get', security=ACCESS_TOKEN)
5256
def get(self, reqno):
5357
try:
5458
post = DB.session.query(Posts).outerjoin(

app/tests/test_crud.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
from http import HTTPStatus
3+
from app.users.models import Users
4+
from app.posts.models import Posts
5+
from app.users.views import USERS_SCHEMA
6+
from app.posts.views import POSTS_SCHEMA
7+
from app.api.database import CRUD
8+
9+
def test_add():
10+
crud = CRUD()
11+
try:
12+
users = Users('test', 'test','test')
13+
result = crud.add(users, USERS_SCHEMA)
14+
except Exception as err:
15+
print(err)
16+
assert True

app/tests/test_practice.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ def test_practice():
1818
except ValueError as err:
1919
message = str(err)
2020
print(message)
21+
result = worker.work()
22+
assert result == "work"

app/users/views.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,77 @@
11
"""
22
User views file
33
"""
4+
import jwt
5+
import bcrypt
46
from http import HTTPStatus
57
from flask import jsonify, make_response
68
from sqlalchemy.exc import SQLAlchemyError
79
from flask_restplus import Namespace, Resource, reqparse, fields
810
from app.users.models import Users, UsersSchema
911
from app.api.database import DB
12+
from app.api.auth_type import SECERET_KEY
1013

1114
API = Namespace('Users', description="User's RESTPlus - API")
1215
USERS_SCHEMA = UsersSchema()
1316

17+
1418
@API.route('s')
1519
class UsersAuth(Resource):
1620
parser = reqparse.RequestParser()
17-
parser.add_argument('user_id', required=True, type=str, help="User's ID", location='json')
18-
parser.add_argument('user_password', required=True, type=str, help="User's PW", location='json')
19-
parser.add_argument('user_email', required=True, type=str, help="User's Email", location='json')
21+
parser.add_argument('user_id', required=True, type=str,
22+
help="User's ID", location='json')
23+
parser.add_argument('user_password', required=True,
24+
type=str, help="User's PW", location='json')
25+
parser.add_argument('user_email', required=True, type=str,
26+
help="User's Email", location='json')
2027

2128
users_field = API.model('userRegister', {
22-
'user_id' : fields.String,
23-
'user_password' : fields.String,
24-
'user_email' : fields.String
29+
'user_id': fields.String,
30+
'user_password': fields.String,
31+
'user_email': fields.String
2532
})
2633

2734
@API.doc('post')
2835
@API.expect(users_field)
2936
def post(self):
3037
args_ = self.parser.parse_args()
31-
user = Users(args_['user_id'], args_['user_password'], args_['user_email'])
38+
password = args_['user_password']
39+
hash_pw = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
40+
user = Users(args_['user_id'], hash_pw, args_['user_email'])
3241
return user.add(user, USERS_SCHEMA)
3342

43+
3444
@API.route('/auth')
3545
class UserAuth(Resource):
3646
parser = reqparse.RequestParser()
37-
parser.add_argument('user_id', required=True, type=str, help="User's ID", location='json')
38-
parser.add_argument('user_password', required=True, type=str, help="User's PW", location='json')
47+
parser.add_argument('user_id', required=True, type=str,
48+
help="User's ID", location='json')
49+
parser.add_argument('user_password', required=True,
50+
type=str, help="User's PW", location='json')
3951

4052
user_login_field = API.model('userLogin', {
41-
'user_id' : fields.String,
42-
'user_password' : fields.String
53+
'user_id': fields.String,
54+
'user_password': fields.String
4355
})
4456

4557
@API.doc('post')
4658
@API.expect(user_login_field)
4759
def post(self):
4860
args_ = self.parser.parse_args()
4961
try:
50-
user = Users.query.filter(Users.user_id == args_['user_id'], Users.user_password == args_['user_password']).first()
51-
body = jsonify({'user_id' : user.user_id})
62+
user = Users.query.filter(Users.user_id == args_['user_id']).first()
63+
if bcrypt.checkpw(args_['user_password'].encode('utf-8'), user.user_password.encode('utf-8')):
64+
# token 발급
65+
payload = {
66+
'user_id' : user.user_id
67+
}
68+
token = jwt.encode(payload, SECERET_KEY, "HS256")
69+
body = jsonify({'access_token': token.decode('utf-8'),'user': user.id})
5270
if user:
5371
code = HTTPStatus.OK
5472
else:
5573
code = HTTPStatus.NOT_FOUND
5674
except SQLAlchemyError as err:
57-
body = jsonify({'message' : str(err)})
75+
body = jsonify({'message': str(err)})
5876
code = HTTPStatus.INTERNAL_SERVER_ERROR
5977
return make_response(body, code.value)

0 commit comments

Comments
 (0)