feat: add toggle Volcengine console login button for sub-accounts
- Add volc_login_allowed field to IAMUser model - Add toggle-volc-login API endpoint - Add toggle button in IAMUserList dropdown menu - Sync status on user creation and toggle Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f79ae0084d
commit
48c55765c8
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.2.21 on 2026-03-28 11:38
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('monitor', '0008_iamuser_login_enabled_iamuser_login_password_hash'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='iamuser',
|
||||||
|
name='volc_login_allowed',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='允许登录火山控制台'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -41,6 +41,7 @@ class IAMUser(models.Model):
|
|||||||
# AirGate 本地登录密码(子账号用来登录 AirGate,与火山控制台无关)
|
# AirGate 本地登录密码(子账号用来登录 AirGate,与火山控制台无关)
|
||||||
login_password_hash = models.CharField('AirGate 登录密码哈希', max_length=256, blank=True)
|
login_password_hash = models.CharField('AirGate 登录密码哈希', max_length=256, blank=True)
|
||||||
login_enabled = models.BooleanField('允许登录 AirGate', default=False)
|
login_enabled = models.BooleanField('允许登录 AirGate', default=False)
|
||||||
|
volc_login_allowed = models.BooleanField('允许登录火山控制台', default=False)
|
||||||
|
|
||||||
# Access keys (stored as JSON list of AK IDs, not secrets)
|
# Access keys (stored as JSON list of AK IDs, not secrets)
|
||||||
access_key_ids = models.JSONField('AccessKey ID 列表', default=list, blank=True)
|
access_key_ids = models.JSONField('AccessKey ID 列表', default=list, blank=True)
|
||||||
|
|||||||
@ -41,7 +41,7 @@ class IAMUserSerializer(serializers.ModelSerializer):
|
|||||||
'alert_thresholds', 'triggered_alerts',
|
'alert_thresholds', 'triggered_alerts',
|
||||||
'effective_alert_thresholds',
|
'effective_alert_thresholds',
|
||||||
'projects', 'monitored_project_count',
|
'projects', 'monitored_project_count',
|
||||||
'login_enabled',
|
'login_enabled', 'volc_login_allowed',
|
||||||
'remark', 'created_at', 'updated_at',
|
'remark', 'created_at', 'updated_at',
|
||||||
]
|
]
|
||||||
read_only_fields = ['user_id', 'access_key_ids', 'status',
|
read_only_fields = ['user_id', 'access_key_ids', 'status',
|
||||||
|
|||||||
@ -18,6 +18,7 @@ urlpatterns = [
|
|||||||
path('iam-users/<int:pk>/', views.iam_user_detail_view),
|
path('iam-users/<int:pk>/', views.iam_user_detail_view),
|
||||||
path('iam-users/<int:pk>/update/', views.iam_user_update_view),
|
path('iam-users/<int:pk>/update/', views.iam_user_update_view),
|
||||||
path('iam-users/<int:pk>/edit-profile/', views.iam_user_edit_profile_view),
|
path('iam-users/<int:pk>/edit-profile/', views.iam_user_edit_profile_view),
|
||||||
|
path('iam-users/<int:pk>/toggle-volc-login/', views.iam_user_toggle_volc_login_view),
|
||||||
path('iam-users/<int:pk>/set-login/', views.iam_user_set_login_view),
|
path('iam-users/<int:pk>/set-login/', views.iam_user_set_login_view),
|
||||||
path('iam-users/<int:pk>/disable/', views.iam_user_disable_view),
|
path('iam-users/<int:pk>/disable/', views.iam_user_disable_view),
|
||||||
path('iam-users/<int:pk>/enable/', views.iam_user_enable_view),
|
path('iam-users/<int:pk>/enable/', views.iam_user_enable_view),
|
||||||
|
|||||||
@ -252,6 +252,7 @@ def iam_user_create_view(request):
|
|||||||
try:
|
try:
|
||||||
svc.create_login_profile(d['username'], password)
|
svc.create_login_profile(d['username'], password)
|
||||||
result_info['login_enabled'] = True
|
result_info['login_enabled'] = True
|
||||||
|
result_info['volc_login_allowed'] = True
|
||||||
except VolcengineAPIError as e:
|
except VolcengineAPIError as e:
|
||||||
if 'InvalidPassword' in str(e):
|
if 'InvalidPassword' in str(e):
|
||||||
# Rollback: delete the user we just created
|
# Rollback: delete the user we just created
|
||||||
@ -292,6 +293,7 @@ def iam_user_create_view(request):
|
|||||||
phone=d.get('phone', ''),
|
phone=d.get('phone', ''),
|
||||||
status=IAMUser.Status.ACTIVE,
|
status=IAMUser.Status.ACTIVE,
|
||||||
access_key_ids=[result_info.get('access_key_id', '')] if result_info.get('access_key_id') else [],
|
access_key_ids=[result_info.get('access_key_id', '')] if result_info.get('access_key_id') else [],
|
||||||
|
volc_login_allowed=result_info.get('volc_login_allowed', False),
|
||||||
)
|
)
|
||||||
|
|
||||||
# 6. Auto-add project if specified
|
# 6. Auto-add project if specified
|
||||||
@ -379,6 +381,48 @@ def iam_user_update_view(request, pk):
|
|||||||
return Response(IAMUserSerializer(user).data)
|
return Response(IAMUserSerializer(user).data)
|
||||||
|
|
||||||
|
|
||||||
|
@api_view(['POST'])
|
||||||
|
def iam_user_toggle_volc_login_view(request, pk):
|
||||||
|
"""切换子账号的火山控制台登录权限"""
|
||||||
|
try:
|
||||||
|
user = IAMUser.objects.get(pk=pk)
|
||||||
|
except IAMUser.DoesNotExist:
|
||||||
|
return Response({'error': 'not_found'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
account = user.volc_account
|
||||||
|
ak = decrypt(account.access_key_enc)
|
||||||
|
sk = decrypt(account.secret_key_enc)
|
||||||
|
iam = IAMService(ak, sk)
|
||||||
|
|
||||||
|
# Check current status
|
||||||
|
try:
|
||||||
|
resp = iam.get_login_profile(user.username)
|
||||||
|
current = resp.get('Result', {}).get('LoginProfile', {}).get('LoginAllowed', False)
|
||||||
|
except VolcengineAPIError as e:
|
||||||
|
if 'LoginProfileNotExist' in str(e):
|
||||||
|
return Response({'message': '该子账号未设置火山控制台密码,无法切换登录状态'},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
raise
|
||||||
|
|
||||||
|
new_status = not current
|
||||||
|
try:
|
||||||
|
iam.update_login_allowed(user.username, new_status)
|
||||||
|
except VolcengineAPIError as e:
|
||||||
|
return Response({'message': f'操作失败: {e}'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
user.volc_login_allowed = new_status
|
||||||
|
user.save(update_fields=['volc_login_allowed'])
|
||||||
|
|
||||||
|
action = '开启' if new_status else '关闭'
|
||||||
|
AlertRecord.objects.create(
|
||||||
|
iam_user=user, alert_type='manual',
|
||||||
|
title=f'{action}火山控制台登录 {user.username}',
|
||||||
|
content=f'操作人: {request.user.username}',
|
||||||
|
)
|
||||||
|
return Response({'message': f'已{action} {user.username} 的火山控制台登录',
|
||||||
|
'volc_login_allowed': new_status})
|
||||||
|
|
||||||
|
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
def iam_user_edit_profile_view(request, pk):
|
def iam_user_edit_profile_view(request, pk):
|
||||||
"""编辑子账号信息(显示名、手机号、邮箱),同步到火山"""
|
"""编辑子账号信息(显示名、手机号、邮箱),同步到火山"""
|
||||||
|
|||||||
@ -79,6 +79,9 @@
|
|||||||
<el-dropdown-item @click="openProjectsDialog(row)">项目管理</el-dropdown-item>
|
<el-dropdown-item @click="openProjectsDialog(row)">项目管理</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openConfig(row)">监控配置</el-dropdown-item>
|
<el-dropdown-item @click="openConfig(row)">监控配置</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openEditProfile(row)">编辑信息</el-dropdown-item>
|
<el-dropdown-item @click="openEditProfile(row)">编辑信息</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="toggleVolcLogin(row)">
|
||||||
|
{{ row.volc_login_allowed ? '🔓 关闭火山登录' : '🔒 开启火山登录' }}
|
||||||
|
</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openPolicies(row)">权限策略</el-dropdown-item>
|
<el-dropdown-item @click="openPolicies(row)">权限策略</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openQuotaHistory(row)">划拨记录</el-dropdown-item>
|
<el-dropdown-item @click="openQuotaHistory(row)">划拨记录</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openSetLogin(row)">登录密码</el-dropdown-item>
|
<el-dropdown-item @click="openSetLogin(row)">登录密码</el-dropdown-item>
|
||||||
@ -475,6 +478,22 @@ async function handleEnable(row) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle Volcengine console login
|
||||||
|
async function toggleVolcLogin(row) {
|
||||||
|
const action = row.volc_login_allowed ? '关闭' : '开启'
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定${action} "${row.username}" 的火山引擎控制台登录?`,
|
||||||
|
`${action}火山登录`, { type: 'warning' }
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
const { data } = await api.post(`/api/v1/iam-users/${row.id}/toggle-volc-login/`)
|
||||||
|
ElMessage.success(data.message)
|
||||||
|
await loadUsers()
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error(e.response?.data?.message || '操作失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Edit Profile
|
// Edit Profile
|
||||||
const editProfileVisible = ref(false)
|
const editProfileVisible = ref(false)
|
||||||
const editProfileUser = ref(null)
|
const editProfileUser = ref(null)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user