Repository navigation
refactor: prevent deletion of the current user in user management #7848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -277,7 +277,11 @@ class Operate(APIView): | |
| get_operation_object=lambda r, k: get_user_operation_object(k.get("user_id")), | ||
| ) | ||
| def delete(self, request: Request, user_id): | ||
| return result.success(UserManageSerializer.Operate(data={"id": user_id}).delete(with_valid=True)) | ||
| return result.success( | ||
| UserManageSerializer.Operate(data={"id": user_id}).delete( | ||
| current_user_id=str(request.user.id), with_valid=True | ||
| ) | ||
| ) | ||
|
|
||
| @extend_schema( | ||
| methods=["GET"], | ||
|
|
@@ -334,7 +338,11 @@ class BatchDelete(APIView): | |
| get_operation_object=lambda r, k: get_user_operation_object(r.data.get("ids", [])), | ||
| ) | ||
| def post(self, request: Request): | ||
| return result.success(UserManageSerializer.BatchDelete({"ids": request.data}).batch_delete(with_valid=True)) | ||
| return result.success( | ||
| UserManageSerializer.BatchDelete({"ids": request.data}).batch_delete( | ||
| current_user_id=str(request.user.id), with_valid=True | ||
| ) | ||
| ) | ||
|
|
||
| class RePassword(APIView): | ||
| authentication_classes = [TokenAuth] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here is the review of the provided code patch: 1. Irregularities & Bugs
2. Potential Issues
3. Optimization & Improvement Suggestions
Suggested Corrected Code (Example for BatchDelete robustness)# Assuming request.data is expected to contain 'ids' key OR is a list of ids
ids = request.data.get("ids") if isinstance(request.data, dict) else request.data
return result.success(
UserManageSerializer.BatchDelete(data={"ids": ids}).batch_delete(
current_user_id=str(request.user.id),
with_valid=True
)
)Summary of Actions
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
Summary of Changes
delete()now takescurrent_user_idand blocks self-deletion.batch_delete()now excludes both the built-in system user and the current user.Issues & Suggestions
1. Security check ordering in
delete()The self-deletion check was moved before
_check_not_admin(). This means a non-admin caller could potentially receive a different error than expected (e.g. "Cannot delete current user" before "not admin"), which is a minor information leak and behavior change. Consider keeping the admin authorization check first:2. Reused error code
1004AppApiException(1004, ...)is used for multiple distinct conditions ("User does not exist", "Cannot delete current user"). Consider using distinct error codes for better client-side handling and observability.3.
batch_delete()has critical gapscurrent_user_idor the system user is included, they're silently skipped. Callers getTrueeven though not all requested deletions happened. Consider returning deleted vs. skipped counts, or raising if the current user is in the list.delete(),batch_delete()doesn't callis_valid()or_check_not_admin(). Even if guarded at the view layer, this is asymmetric and easy to regress — add an explicit authorization guard for defense in depth."f0dd8f71-e4ee-11ee-8c84-a8a1595801ab"is a magic string. Extract it to a module constant (e.g.SYSTEM_USER_ID) so bothdelete()andbatch_delete()share it — also notedelete()currently does not protect the system user, onlybatch_delete()does. That's an inconsistency bug.str(current_user_id)insideid__inis fine, but building the exclusion list once improves readability.Suggested refactor:
And make
delete()use the sameSYSTEM_USER_IDguard.4. Missing cascade cleanup
The existing
# TODO 需要删除授权关系(delete authorization relations) still applies. Both delete paths leave orphaned permission/workspace relations. Deletions should be wrapped consistently so relations are cleaned up; otherwise batch delete compounds the orphan issue.5. Race condition on mass delete
filter(...).delete()is atomic per-Django, but there's no transaction decorator onBatchDelete.batch_delete(unlikedelete's@transaction.atomic). If relation cleanup is added later, wrap it intransaction.atomicfor consistency.6. Callers must be updated
Both signatures changed (added a required positional param). Verify all call sites — views, serializers, tests, and any internal helpers — pass
current_user_id. A missing arg would raiseTypeErrorat runtime.7. Type coercion
str(user_id) == str(current_user_id)handles UUID vs string mismatches, but it's cleaner to normalize IDs at input validation (self.is_valid) so downstream comparisons are type-safe.Priority fixes: shared
SYSTEM_USER_IDconstant + apply system-user protection indelete()(#3), authorization guard inbatch_delete(#3), and update all callers (#6).