GraphQL 인증 및 Graphene, SQLAlchemy 및 oso
많은 개발자들이 응용 프로그램에서 권한을 부여받는 출발점으로 루트 등급 검사를 하는 것을 보았다.흔히 볼 수 있는 모델은 루트 코드를 실행하기 전에 장식기나 다른 루트 단계의 보호를 사용하여 사용자가 특정한 요구를 충족시킬 수 있도록 하는 것이다(사용자는 관리자이고 사용자는 특정한 역할을 가진다).
이런 방법은 입문하기 쉬우나GraphQL에서는 통상적으로 불가능하다.GraphQL 응용 프로그램에는 잠재적인 데이터 집합이 고도로 변환될 수 있는 경로가 있습니다.GraphQL 쿼리의 필드 조합은 일반적인 REST 응용 프로그램보다 훨씬 많습니다.
GraphQL은 단일 데이터 요소에 대한 접근을 위한 것이기 때문에 권한을 수행하는 자연스러운 장소는 데이터 접근 기간이다.GraphQL의 공식 파일 승인:
Where should you perform validation and authorization checks? The answer: inside a dedicated business logic layer. Your business logic layer should act as the single source of truth for enforcing business domain rules [emphasis added].
– https://graphql.org/learn/thinking-in-graphs/#business-logic-layer
위대했어쉬웠어그런데 이게 도대체 어떻게 된 일입니까?우리는 어떻게 업무 영역 규칙을 집행합니까?그것들을 지정하기 위한 간단한 추상이 있습니까?
본고에서 우리는 oso를 소스 권한 수여 라이브러리로 사용하여 권한 수여 규칙을 강제적으로 집행하는 방법을 소개할 것이다.우리는 oso의 정책 언어인 Polar로 권한 수여 규칙을 성명적으로 지정하는 방법과 몇 줄의 코드만으로 oso를GraphQL 응용 프로그램에 집적하는 방법을 보게 될 것이다.
우리는 SQLAlchemy를 ORM으로 사용하고Graphene - 유행하는 Python GraphQL 라이브러리를 사용할 것이다.
sqlalchemy-oso
library은 oso,GraphQL,SQLAlchemy 사이에 접착제를 제공하여 권한 수여 일치성을 강제로 집행할 수 있도록 합니다.설정
비용 관리 애플리케이션을 나타내는 기본 Flask 애플리케이션부터 시작하겠습니다.다음은 clone the project on GitHub.이 프로그램의 권한 수여와 관련된 부분을 훑어보겠지만, 전체 코드는 프로젝트에서 얻을 수 있습니다.우리는 당신이 Flask, SQLAlchemy,GraphQL에 대해 어느 정도 알고 있다고 가정합니다.본 문서의 모든 부분은 저장소의 제출을 바탕으로 하고 이 부분의 시작은 관련 제출에 연결됩니다.
만약 읽는 과정에서 이 예시들을 계속 시도하고 시도할 계획이라면, 코드를 실행하기 위해 README에 의존항을 설치해야 합니다.이 섹션에서는 initial commit에 대해 설명합니다.
EMC 애플리케이션의 모델 번호는 다음과 같습니다.
비용: 사용자가 만든 비용.
사용자: 응용 프로그램에 액세스한 사용자입니다.
models.py
모델입니다.이것들은 일반적인 연금술 모형들이오.flask_sqlalchemy 라이브러리를 Flask와 통합하여 설치를 단순화했습니다.from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import relationship
db = SQLAlchemy()
class Expense(db.Model):
__tablename__ = 'expenses'
id = db.Column(db.Integer, primary_key=True)
amount = db.Column(db.Integer)
created_by_id = db.Column(db.Integer, db.ForeignKey('users.id'))
created_by = relationship("User")
description = db.Column(db.Text)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(256))
비용은 사용자가 만들고 Expense.created_by
속성에서 획득할 수 있습니다.app/schema.py
에서는 그래핀을 사용하여 이러한 모델에 GraphQL 모델을 정의했습니다.import graphene
from graphene import relay
from graphene_sqlalchemy import SQLAlchemyConnectionField, SQLAlchemyObjectType
from flask import g
from . import models
class Expense(SQLAlchemyObjectType):
class Meta:
model = models.Expense
interfaces = (relay.Node,)
class User(SQLAlchemyObjectType):
class Meta:
model = models.User
interfaces = (relay.Node,)
class Query(graphene.ObjectType):
expenses = SQLAlchemyConnectionField(Expense.connection)
user = graphene.Field(User)
node = graphene.relay.Node.Field()
def resolve_user(parent, info):
return (g.current_user
if isinstance(g.current_user, models.User)
else None)
# ... snip ...
schema = graphene.Schema(query=Query)
이 모드는 Graphene-SQLAlchemy library을 사용하여 SQLAlchemy 모델에 그래핀 모드 대상을 만듭니다.SQLAlchemy와 그래핀을 결합해 사용하는 standard approach이다.우리는 간단한 조회를 할 수 있다. (나는 아주 좋은 GraphiQL 도구를 사용하지만, 너도 브라우저에서 http://localhost:5000/graphql으로 이동해서 우리의 응용 프로그램이 정상적으로 작동하는지 볼 수 있다.)
라이센스 추가
현재 GraphQL 응용 프로그램은 권한이 부여되지 않았습니다.우리 안배해 봅시다.commit on GitHub입니다.
우리의 최초의 권한 수여 규칙은 데이터 소유자의 개념을 바탕으로 한다. 사용자는 자신의 비용을 볼 수 있다.
이 규칙을 실현하기 위해서는 SQLAlchemy 단계에서 필터를 실행해야 합니다.즉,
대신
sqlalchemy-oso
라이브러리를 사용합니다.이 설정을 설정하려면 두 가지 변경 사항이 필요합니다.Oso
의 실례를 저희 프로그램에 추가합니다.create_app
함수를 수정합니다.from oso import Oso
from sqlalchemy_oso import register_models
def create_app():
# snip ...
# Create oso instance which will hold our policy.
oso = Oso()
# Make SQLAlchemy models available in the policy.
register_models(oso, db.Model)
# Load policy file into oso.
oso.load_file(Path(__file__).parent / "policy.polar")
# ...
그런 다음 애플리케이션의 SQLAlchemy
객체를 AuthorizedSQLAlchemy
으로 교체합니다.models.py
:from sqlalchemy_oso.flask import AuthorizedSQLAlchemy
db = AuthorizedSQLAlchemy(
get_oso=lambda: current_app.oso,
get_user=lambda: getattr(g, "current_user", None),
get_action=lambda: "read"
)
우리는 이 대상을 flask_sqlalchemy.SQLAlchemy
이 아니라 사용한다.이것은 조회를 필터할 수 있는 SQLAlchemy Session object을 제공하여 현재 사용자와 조작 권한 수여 대상으로만 되돌려줍니다.우리의 정책 문건은 현재 비어 있다.
이제 질의 결과를 검토해 보겠습니다.
다시는 아무도 돌아오지 않을 것이다.왜?정책 파일이 비어 있습니다.Polar는 기본적으로 deny이므로 규칙을 추가해야 합니다.우리가 이렇게 하기 전에, 우리가 이것이 어떻게 일을 하는지 좀 봅시다.마지막 질의를 수행하는 데 사용된 SQL을 기록하는 엔드포인트가 있습니다.따라가는 경우 다음 도구를 사용하여 응용 프로그램을 실행합니다.
$ FLASK_RUN_EXTRA_FILES=app/policy.polar FLASK_DEBUG=1 flask run
GraphiQL에서 질의를 실행합니다.다음은 좋은 출발점이다.{
expenses {
edges {
node {
id
description
createdBy {
email
}
}
}
}
}
지금 http://localhost:5000/sql을 방문하십시오.여기서 우리는 다음과 같이 보았다.
SELECT count(*) AS count_1
FROM (
SELECT expenses.id AS expenses_id,
expenses.amount AS expenses_amount,
expenses.created_by_id AS expenses_created_by_id,
expenses.description AS expenses_description
FROM expenses
WHERE 0 = 1
ORDER BY expenses.id ASC
) AS anon_1
WHERE 자구: app/policy.polar
을 참고하십시오.그거 어디서 났어요?0 = 1
은 정책의 규칙을 SQL 필터로 변환하여 Polar 정책을 구현합니다.sqlalchemy-oso
은 항상false로 데이터베이스에서 어떤 기록도 되돌려주지 않습니다.규칙 추가
현재 우리는 oso를 통합하여 권한 수여 규칙의 실현을 완성했다.어플리케이션 실행을 유지합니다.
0 = 1
환경 변수를 설정하면 정책을 변경할 때 Flask에서 어플리케이션을 다시 로드할 수 있습니다.FLASK_RUN_EXTRA_FILES
에서 다음을 시도해 보겠습니다.allow(_actor, _action, _resource);
이 정책은 사용자가 모든 대상에 접근할 수 있도록 합니다.Polar에서 정책의 각 문은 규칙이라고 합니다.app/policy.polar
규칙은 특수한 규칙으로 전략의 입구점으로 사용된다.이것은 세 가지 인자가 있는데, actor (요청한 사람), action (요청이 무엇을 할 것인지), Resource (요청 작업의 대상) 이다.우리의 정책에는 규칙이 하나 있다.모든 매개 변수는 allow
으로 시작하여 익명 변수를 표시합니다. (제약이 없기 때문에 모든 변수와 일치하는 변수입니다.)쿼리를 다시 실행하고 SQL을 확인하십시오(http://localhost:5000/sql을 새로 고치기만 하면 됩니다.GraphQL 쿼리를 해석하기 위한 주요 SQL 쿼리를 선택했습니다.
SELECT expenses.id AS expenses_id,
expenses.amount AS expenses_amount,
expenses.created_by_id AS expenses_created_by_id,
expenses.description AS expenses_description
FROM expenses
WHERE 1 = 1
ORDER BY expenses.id ASC
LIMIT 4
OFFSET 0
지금 우리는 _
을 보았다.이것은 영원히 정말이다!결국 모든 물건이 돌려주었다.한 단계 더 나아가겠습니다.
allow(_: User, "read", _: Expense);
이 정책은 모든 사용자가 모든 비용을 읽을 수 있도록 규정하고 있다.마찬가지로 WHERE 1 = 1
은 익명이나 무시된 변수를 표시하지만 _
문법은 입력 데이터가 특정 유형과 일치하는지 검사합니다.이 예에서 사용자와 비용 모델은 우리의 models.py 파일에서 나온 것이다.다음은 반환된 데이터입니다.
각 비용의
: User
필드는 현재 createdBy
입니다.우리는 null
자원의 규칙이 없기 때문에 사용자는 어떠한 비용도 볼 수 없습니다.User
에 규칙을 추가합니다.allow(_: User, "read", _: Expense);
allow(_: User, "read", _: User);
상술한 보증서는 this commit on GitHub.이다이제 사용자는 자신의 비용을 볼 수 있다는 규칙을 살펴봅시다.극좌표 규칙에는
User
키워드로 표시된 바디가 있을 수 있습니다.여기에는 사용자의 요구 사항을 충족하는 규칙이 있습니다. 비용이 사용자에 의해 만들어진 경우 사용자는 비용을 읽을 수 있습니다.allow(user: User, "read", expense: Expense) if
expense.created_by = user;
allow(_: User, "read", _: User);
SQL:
SELECT expenses.id AS expenses_id,
expenses.amount AS expenses_amount,
expenses.created_by_id AS expenses_created_by_id,
expenses.description AS expenses_description
FROM expenses
WHERE 1 = expenses.created_by_id
ORDER BY expenses.id ASC
LIMIT 2
OFFSET 0
지금 우리는 if
을 보았다.WHERE 1 = expenses.created_by_id
은 현재 사용자의 id입니다.우리의 정책은 이미 SQL로 바뀌었다!this commit to run it 보기!한층 더
지금까지 우리는 작은 정책 예시를 보여 주었다.oso는 GraphQL에서만 간단한 장식기를 사용할 수 없지만 권한 수여 규칙을 일치된 추상적으로 표현해 줍니다.그것을 실현하기 위해서, 우리는 해상도를 수정할 필요도, 새로운 해상도를 작성할 필요도 없다.Polar와GraphQL은 모두 문제 영역을 해결하는 성명적인 방법이다. Polar는 권한 수여 규칙을 성명하는 추상화를 제공하고GraphQL은 백엔드에서 데이터를 얻는 성명적인 추상화를 제공한다.
자세한 내용을 보려면 샘플 애플리케이션 here에서 이 정책을 살펴보겠습니다.이 정책은 다음과 같다.
Install은
1
고입니다.Join our Slack 우리 엔지니어링 팀과 채팅.우리는 본문에서 토론한 기능을 빠르게 확장하고 있으며, 당신의 용례를 이해하기를 바랍니다.
Reference
이 문제에 관하여(GraphQL 인증 및 Graphene, SQLAlchemy 및 oso), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/dhatch/graphql-authorization-with-graphene-sqlalchemy-and-oso-5fhi텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)