forked from kompetenzinventar/ki-backend
implement login
This commit is contained in:
parent
3920183e0c
commit
c33c08fe0a
1
Pipfile
1
Pipfile
@ -12,6 +12,7 @@ sqlalchemy = "*"
|
|||||||
waitress = "*"
|
waitress = "*"
|
||||||
|
|
||||||
[dev-packages]
|
[dev-packages]
|
||||||
|
pyyaml = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.8"
|
python_version = "3.8"
|
||||||
|
40
Pipfile.lock
generated
40
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "88e5fb21e69421ebb5788f9c47069d778f9b87246dc340eae094275fb4873d1b"
|
"sha256": "1a3f310d3d4b4507d76b8074a0580f84ab15774f21edc1f178f2eb736d2c3467"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {
|
"requires": {
|
||||||
@ -262,5 +262,41 @@
|
|||||||
"version": "==2.0.1"
|
"version": "==2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"develop": {}
|
"develop": {
|
||||||
|
"pyyaml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf",
|
||||||
|
"sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696",
|
||||||
|
"sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393",
|
||||||
|
"sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77",
|
||||||
|
"sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922",
|
||||||
|
"sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5",
|
||||||
|
"sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8",
|
||||||
|
"sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10",
|
||||||
|
"sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc",
|
||||||
|
"sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018",
|
||||||
|
"sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e",
|
||||||
|
"sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253",
|
||||||
|
"sha256:72a01f726a9c7851ca9bfad6fd09ca4e090a023c00945ea05ba1638c09dc3347",
|
||||||
|
"sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183",
|
||||||
|
"sha256:895f61ef02e8fed38159bb70f7e100e00f471eae2bc838cd0f4ebb21e28f8541",
|
||||||
|
"sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb",
|
||||||
|
"sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185",
|
||||||
|
"sha256:bfb51918d4ff3d77c1c856a9699f8492c612cde32fd3bcd344af9be34999bfdc",
|
||||||
|
"sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db",
|
||||||
|
"sha256:cb333c16912324fd5f769fff6bc5de372e9e7a202247b48870bc251ed40239aa",
|
||||||
|
"sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46",
|
||||||
|
"sha256:d483ad4e639292c90170eb6f7783ad19490e7a8defb3e46f97dfe4bacae89122",
|
||||||
|
"sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b",
|
||||||
|
"sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63",
|
||||||
|
"sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df",
|
||||||
|
"sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc",
|
||||||
|
"sha256:fd7f6999a8070df521b6384004ef42833b9bd62cfee11a09bda1079b4b704247",
|
||||||
|
"sha256:fdc842473cd33f45ff6bce46aea678a54e3d21f1b61a7750ce3c498eedfe25d6",
|
||||||
|
"sha256:fe69978f3f768926cfa37b867e3843918e012cf83f680806599ddce33c2c68b0"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==5.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
34
README.md
34
README.md
@ -11,15 +11,47 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
cp env.dev .env
|
cp env.dev .env
|
||||||
pipenv install
|
pipenv install --dev
|
||||||
pipenv shell
|
pipenv shell
|
||||||
export FLASK_APP=app.py
|
export FLASK_APP=app.py
|
||||||
flask db upgrade
|
flask db upgrade
|
||||||
|
flask seed
|
||||||
flask run
|
flask run
|
||||||
```
|
```
|
||||||
|
|
||||||
http://localhost:5000/
|
http://localhost:5000/
|
||||||
|
|
||||||
|
|
||||||
|
### Testbenutzer
|
||||||
|
|
||||||
|
Für ein Login ohne LDAP werden die Benutzer aus der [`auth.yml`](./data/auth.yml) benutzt.
|
||||||
|
|
||||||
|
|
||||||
|
### Test-Requests
|
||||||
|
|
||||||
|
Beispiele brauchen curl und jq.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -s \
|
||||||
|
-D "/dev/stderr" \
|
||||||
|
http://localhost:5000/skills?search=ph | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -s \
|
||||||
|
-D "/dev/stderr" \
|
||||||
|
http://localhost:5000/languages?search=fr | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -s \
|
||||||
|
-D "/dev/stderr" \
|
||||||
|
-X POST \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"username": "peter", "password": "geheim"}' \
|
||||||
|
http://localhost:5000/users/login | jq
|
||||||
|
```
|
||||||
|
|
||||||
### Produktionsumgebung
|
### Produktionsumgebung
|
||||||
|
|
||||||
Für die Produktionsumgebung wird [waitress](https://docs.pylonsproject.org/projects/waitress/en/latest/) benutzt.
|
Für die Produktionsumgebung wird [waitress](https://docs.pylonsproject.org/projects/waitress/en/latest/) benutzt.
|
||||||
|
1
app.py
1
app.py
@ -11,6 +11,7 @@ app = Flask(__name__)
|
|||||||
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("SQLALCHEMY_DATABASE_URI")
|
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("SQLALCHEMY_DATABASE_URI")
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
app.config["KI_DATA_DIR"] = os.path.dirname(__file__) + "/data"
|
app.config["KI_DATA_DIR"] = os.path.dirname(__file__) + "/data"
|
||||||
|
app.config["KI_AUTH"] = os.getenv("KI_AUTH")
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
migrate = Migrate(app, db)
|
migrate = Migrate(app, db)
|
||||||
|
|
||||||
|
3
data/auth.yml
Normal file
3
data/auth.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
peter:
|
||||||
|
password: geheim
|
2
env.dev
2
env.dev
@ -1 +1,3 @@
|
|||||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///data/ki.sqlite'
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///data/ki.sqlite'
|
||||||
|
|
||||||
|
KI_AUTH=file
|
||||||
|
32
ki/auth.py
Normal file
32
ki/auth.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import uuid
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from app import app, db
|
||||||
|
from ki.models import User, Token
|
||||||
|
|
||||||
|
|
||||||
|
def auth(username, password):
|
||||||
|
auth_file_path = app.config["KI_DATA_DIR"] + "/auth.yml"
|
||||||
|
|
||||||
|
with open(auth_file_path, "r") as auth_file_stream:
|
||||||
|
users = yaml.safe_load(auth_file_stream)
|
||||||
|
|
||||||
|
if username not in users:
|
||||||
|
return None
|
||||||
|
|
||||||
|
auth_user = users[username]
|
||||||
|
|
||||||
|
if auth_user["password"] != password:
|
||||||
|
return None
|
||||||
|
|
||||||
|
user = User.query.filter(User.auth_id.__eq__(username)).first()
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
user = User(nickname=username, auth_id=username)
|
||||||
|
db.session.add(user)
|
||||||
|
|
||||||
|
token = Token(token=str(uuid.uuid4()), user=user)
|
||||||
|
db.session.add(token)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
return token
|
14
ki/models.py
14
ki/models.py
@ -14,15 +14,15 @@ class User(db.Model):
|
|||||||
pronouns = Column(String(25), default="")
|
pronouns = Column(String(25), default="")
|
||||||
volunteerwork = Column(String(4000), default="")
|
volunteerwork = Column(String(4000), default="")
|
||||||
freetext = Column(String(4000), default="")
|
freetext = Column(String(4000), default="")
|
||||||
created = Column(DateTime, nullable=False)
|
created = Column(DateTime, nullable=False, default=datetime.now)
|
||||||
updated = Column(DateTime, onupdate=datetime.now, nullable=False)
|
updated = Column(DateTime, onupdate=datetime.now, nullable=False, default=datetime.now)
|
||||||
auth_id = Column(String(50), nullable=False)
|
auth_id = Column(String(50), nullable=False, unique=True)
|
||||||
|
|
||||||
contacts = relationship("Contact")
|
contacts = relationship("Contact")
|
||||||
address = relationship("Address", uselist=False, back_populates="user")
|
address = relationship("Address", uselist=False, back_populates="user")
|
||||||
tokens = relationship("Token", uselist=False, back_populates="user")
|
tokens = relationship("Token", uselist=False, back_populates="user")
|
||||||
skills = relationship("UserSkill", back_populates="users")
|
skills = relationship("UserSkill", back_populates="user")
|
||||||
languages = relationship("UserLanguage", "users")
|
languages = relationship("UserLanguage", back_populates="user")
|
||||||
|
|
||||||
|
|
||||||
class Token(db.Model):
|
class Token(db.Model):
|
||||||
@ -75,7 +75,7 @@ class Skill(db.Model):
|
|||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
name = Column(String(25), unique=True, nullable=False)
|
name = Column(String(25), unique=True, nullable=False)
|
||||||
|
|
||||||
users = relationship("User", back_populates="skills")
|
users = relationship("UserSkill", back_populates="skill")
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {"id": self.id, "name": self.name}
|
return {"id": self.id, "name": self.name}
|
||||||
@ -98,7 +98,7 @@ class Language(db.Model):
|
|||||||
id = Column(String(2), primary_key=True)
|
id = Column(String(2), primary_key=True)
|
||||||
name = Column(String(25), nullable=False)
|
name = Column(String(25), nullable=False)
|
||||||
|
|
||||||
users = relationship("UserLanguage", back_populates="languages")
|
users = relationship("UserLanguage", back_populates="language")
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {"id": self.id, "name": self.name}
|
return {"id": self.id, "name": self.name}
|
||||||
|
14
ki/routes.py
14
ki/routes.py
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from flask import make_response, request, send_file
|
from flask import jsonify, make_response, request, send_file
|
||||||
|
|
||||||
|
from ki.auth import auth
|
||||||
from ki.models import Language, Skill
|
from ki.models import Language, Skill
|
||||||
from app import app
|
from app import app
|
||||||
|
|
||||||
@ -64,6 +65,17 @@ def handle_icon_request(model, id, path):
|
|||||||
def hello_world():
|
def hello_world():
|
||||||
return "KI"
|
return "KI"
|
||||||
|
|
||||||
|
@app.route("/users/login", methods=["POST"])
|
||||||
|
def login():
|
||||||
|
username = request.json.get("username", "")
|
||||||
|
password = request.json.get("password", "")
|
||||||
|
token = auth(username, password)
|
||||||
|
|
||||||
|
if token is None:
|
||||||
|
return make_response({}, 403)
|
||||||
|
|
||||||
|
return make_response({"token": token.token})
|
||||||
|
|
||||||
|
|
||||||
@app.route("/skills")
|
@app.route("/skills")
|
||||||
def get_skills():
|
def get_skills():
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"""Initial migration
|
"""Initial migration
|
||||||
|
|
||||||
Revision ID: 47ba0a9cf065
|
Revision ID: 575a8924eb16
|
||||||
Revises:
|
Revises:
|
||||||
Create Date: 2021-06-12 12:06:29.946450
|
Create Date: 2021-06-12 13:18:24.903142
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from alembic import op
|
from alembic import op
|
||||||
@ -10,7 +10,7 @@ import sqlalchemy as sa
|
|||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '47ba0a9cf065'
|
revision = '575a8924eb16'
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@ -44,6 +44,7 @@ def upgrade():
|
|||||||
sa.Column('updated', sa.DateTime(), nullable=False),
|
sa.Column('updated', sa.DateTime(), nullable=False),
|
||||||
sa.Column('auth_id', sa.String(length=50), nullable=False),
|
sa.Column('auth_id', sa.String(length=50), nullable=False),
|
||||||
sa.PrimaryKeyConstraint('id'),
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('auth_id'),
|
||||||
sa.UniqueConstraint('nickname')
|
sa.UniqueConstraint('nickname')
|
||||||
)
|
)
|
||||||
op.create_table('address',
|
op.create_table('address',
|
Loading…
Reference in New Issue
Block a user