Skip to content

Commit

Permalink
feat: support tenant mode (#205)
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesgetx authored Dec 20, 2024
1 parent e16377d commit a1fa355
Show file tree
Hide file tree
Showing 17 changed files with 331 additions and 276 deletions.
3 changes: 3 additions & 0 deletions sdks/bkpaas-auth/CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# 版本历史

## 3.1.0
- feat: UniversalAuthBackend 支持获取用户租户身份信息

## 3.0.0
- BreakChange: 不再支持 Python 3.6,3.7
- BreakChange: Django 版本要求 >=4.2,<5.0
Expand Down
18 changes: 18 additions & 0 deletions sdks/bkpaas-auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,22 @@ BKAUTH_USER_COOKIE_VERIFY_URL = "http://bk-login-web/api/v3/is_login/"
BKAUTH_DEFAULT_PROVIDER_TYPE = 'RTX' # 可选值:RTX/UIN/BK,详见 ProviderType
```

启用多租户模式时, 需要更新上面的 settings
```python
# 启用多租户模式
BKAUTH_ENABLE_MULTI_TENANT_MODE = True

# 用户登录态认证类型
BKAUTH_BACKEND_TYPE = "bk_token" # 只能选择:bk_token

# 验证用户信息的网关 API(租户版本)
# 如 BK_API_URL_TMPL.format(api_name="bk-login") + "/prod/login/api/v3/open/bk-tokens/userinfo/"
BKAUTH_USER_INFO_APIGW_URL = ""

# [可选]`BKAUTH_DEFAULT_PROVIDER_TYPE` 的值用于 JWT 校验时获取默认的用户认证类型。
BKAUTH_DEFAULT_PROVIDER_TYPE = 'BK' # 只能选择:BK
```

2. 在 app config 中进行 patch:

配置登录模块的 apps.py
Expand Down Expand Up @@ -131,6 +147,8 @@ class YourDjangoAuthUserCompatibleBackend(DjangoAuthUserCompatibleBackend):
return db_user
```

> 说明: 启用多租户模式后, user 会增加 tenant_id 和 display_name 两个字段,可以通过 `request.user.tenant_id` 获取租户 ID, 通过 `request.user.display_name` 获取用户展示名。
#### [apigw-manager](../apigw-manager) 集成
该 SDK 可以和 apigw-manager 集成,完成网关 JWT 的校验,在 settings 中配置:
```python
Expand Down
180 changes: 0 additions & 180 deletions sdks/bkpaas-auth/README.rst

This file was deleted.

8 changes: 7 additions & 1 deletion sdks/bkpaas-auth/bkpaas_auth/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
# -*- coding: utf-8 -*-
__version__ = "3.0.0"
__version__ = "3.1.0"


def get_user_by_user_id(user_id: str, username_only: bool = True):
"""Get a user object from given user_id"""
from bkpaas_auth.conf import bkauth_settings as conf
from bkpaas_auth.core.constants import ProviderType
from bkpaas_auth.core.encoder import user_id_encoder
from bkpaas_auth.core.services import get_bk_user_info, get_rtx_user_info
from bkpaas_auth.models import User

provider_type, username = user_id_encoder.decode(user_id)
user = User(token=None, provider_type=ProviderType(provider_type), username=username)

if username_only:
return user

# 多租户模式下, 暂时没有根据用户名获取用户详细信息的接口
if conf.ENABLE_MULTI_TENANT_MODE:
raise ValueError('Multi-tenant mode only return username, please set username_only=True')

# Request third party service to get info other than username
if provider_type == ProviderType.RTX:
user_info = get_rtx_user_info(username)
Expand Down
28 changes: 23 additions & 5 deletions sdks/bkpaas-auth/bkpaas_auth/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@

from bkpaas_auth.conf import bkauth_settings
from bkpaas_auth.core.constants import ProviderType
from bkpaas_auth.core.exceptions import InvalidTokenCredentialsError, ServiceError
from bkpaas_auth.core.exceptions import InvalidTokenCredentialsError, ResponseError, ServiceError
from bkpaas_auth.core.plugins import BkTicketPlugin, BkTokenPlugin
from bkpaas_auth.core.token import (
LoginToken,
RequestBackend,
TokenRequestBackend,
UserAccount,
create_user_from_token,
mocked_create_user_from_token,
)
Expand Down Expand Up @@ -53,19 +54,33 @@ def __init__(self):

def authenticate(self, request: HttpRequest, auth_credentials: Dict) -> Optional[Union[User, AnonymousUser]]:
try:
username = self.request_backend.request_username(**auth_credentials)
user_account: UserAccount = self.request_backend.request_user_account(**auth_credentials)

if bkauth_settings.ENABLE_MULTI_TENANT_MODE and not user_account.tenant_id:
raise ImproperlyConfigured(
"No tenant information found. You may check whether BKAUTH_USER_INFO_APIGW_URL is set to "
"correct gateway url that can retrieve the user's tenant information"
)

login_token = generate_random_token()
token = LoginToken(
login_token=login_token,
expires_in=bkauth_settings.LOGIN_TOKEN_EXPIRE_IN,
)
token.user_info = UserInfo(username=username)
token.user_info = UserInfo(
username=user_account.bk_username,
display_name=user_account.display_name,
tenant_id=user_account.tenant_id,
)
logger.debug("New login token exchanged by credentials")
except ResponseError as e:
logger.warning(f"authenticate error: {e}")
return None
except InvalidTokenCredentialsError:
logger.warning("authenticate error, invalid credentials given")
logger.warning("authenticate error: invalid credentials given")
return None
except ServiceError:
logger.warning("authenticate error, Error requesting third-party API service")
logger.warning("authenticate error: unable to request backend services")
return None

return self.get_user_by_token(token)
Expand Down Expand Up @@ -164,6 +179,9 @@ def connect_to_django_user(self, user: User):
db_user.provider_type = user.provider_type
db_user.bkpaas_user_id = user.bkpaas_user_id
db_user.token = user.token
db_user.display_name = getattr(user, "display_name", user.username)
db_user.tenant_id = getattr(user, "tenant_id", None)

return db_user

def configure_user(self, db_user, bk_user: User):
Expand Down
20 changes: 20 additions & 0 deletions sdks/bkpaas-auth/bkpaas_auth/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class Settings:
# 验证用户登录态的 API,如 蓝鲸统一登录校验登录态的 API
USER_COOKIE_VERIFY_URL: str = field(default_factory=get_settings('USER_COOKIE_VERIFY_URL'))

# 是否使用多租户模式
ENABLE_MULTI_TENANT_MODE: bool = field(default_factory=get_settings("ENABLE_MULTI_TENANT_MODE", default=False))
# 验证用户信息的网关 API
USER_INFO_APIGW_URL: str = field(default_factory=get_settings("USER_INFO_APIGW_URL"))

# 获取用户详情的 API,如中文名、邮箱等,且必须提供应用鉴权信息
TOKEN_USER_INFO_ENDPOINT: str = field(default_factory=get_settings('TOKEN_USER_INFO_ENDPOINT'))
TOKEN_APP_CODE: str = field(default_factory=get_settings('TOKEN_APP_CODE'))
Expand All @@ -47,6 +52,20 @@ class Settings:
USE_MOCKED_USER_INFO: bool = field(default_factory=get_settings('USE_MOCKED_USER_INFO', default=False))
MOCKED_USER_NAME: str = field(default_factory=get_settings('MOCKED_USER_NAME', default=''))

def __post_init__(self):
self.validate()

def validate(self):
if self.ENABLE_MULTI_TENANT_MODE:
if self.BACKEND_TYPE == "bk_ticket":
raise ImproperlyConfigured(
"BKAUTH_ENABLE_MULTI_TENANT_MODE cannot be True when BKAUTH_BACKEND_TYPE is 'bk_ticket'"
)
if not self.USER_INFO_APIGW_URL:
raise ImproperlyConfigured(
"BKAUTH_USER_INFO_APIGW_URL must be set correctly when BKAUTH_ENABLE_MULTI_TENANT_MODE is True"
)

def reload(self):
for f in fields(self):
setattr(self, f.name, f.default_factory()) # type: ignore
Expand All @@ -59,6 +78,7 @@ def reload_settings(*args, **kwargs):
setting: str = kwargs['setting']
if setting.startswith("BKAUTH_"):
bkauth_settings.reload()
bkauth_settings.validate()


setting_changed.connect(reload_settings)
8 changes: 8 additions & 0 deletions sdks/bkpaas-auth/bkpaas_auth/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ class ServiceError(Exception):
"""Login or Token service is not available"""


class HttpRequestError(Exception):
"""http request error"""


class ResponseError(Exception):
"""service response error"""


class InvalidSkeyError(Exception):
"""Invalid uin/skey given"""

Expand Down
Loading

0 comments on commit a1fa355

Please sign in to comment.