using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
string giteaUrl = "https://<Gitea>/"; // 请替换为 Gitea 服务器地址
string apiToken = "<apiToken>"; // 请替换为你的 API Token
string[] NotDeleteUser = ["6589jk", "wh"];
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", apiToken);
var usersResponse = await client.GetAsync($"{giteaUrl}/api/v1/admin/users");
if (usersResponse.IsSuccessStatusCode)
{
var usersJson = await usersResponse.Content.ReadAsStringAsync();
var users = JsonSerializer.Deserialize<User[]>(usersJson);
await Parallel.ForEachAsync(users, new ParallelOptions
{
MaxDegreeOfParallelism = 4 // 最多同时并发 4 个任务
}, async (user, _) =>
{
var username = user.username;
if (!NotDeleteUser.Contains(username))
{
//Console.WriteLine($"正在处理用户:{username}");
await DeleteUserRepositories(username);
var deleteUserResponse = await client.DeleteAsync($"{giteaUrl}/api/v1/admin/users/{username}");
if (deleteUserResponse.StatusCode == System.Net.HttpStatusCode.NoContent)
{
Console.WriteLine($"✅ 用户 {username} 删除成功。");
}
else
{
Console.WriteLine($"❌ 删除用户 {username} 失败。状态码:{deleteUserResponse.StatusCode}");
}
}
else
{
//Console.WriteLine($"保留用户:{username}");
}
});
}
else
{
Console.WriteLine($"❌ 获取用户列表失败。状态码:{usersResponse.StatusCode}");
}
async Task DeleteUserRepositories(string username)
{
var reposResponse = await client.GetAsync($"{giteaUrl}/api/v1/users/{username}/repos");
if (reposResponse.IsSuccessStatusCode)
{
var reposJson = await reposResponse.Content.ReadAsStringAsync();
var repos = JsonSerializer.Deserialize<Repository[]>(reposJson);
foreach (var repo in repos)
{
var repoName = repo.name;
var deleteRepoResponse = await client.DeleteAsync($"{giteaUrl}/api/v1/repos/{username}/{repoName}");
if (deleteRepoResponse.StatusCode == System.Net.HttpStatusCode.NoContent)
{
Console.WriteLine($"✅ 仓库 {repoName} 删除成功。");
}
else
{
Console.WriteLine($"❌ 删除仓库 {repoName} 失败。状态码:{deleteRepoResponse.StatusCode}");
}
}
}
else
{
Console.WriteLine($"❌ 获取用户 {username} 的仓库失败。状态码:{reposResponse.StatusCode}");
}
}
public class User
{
public string username { get; set; }
}
public class Repository
{
public string name { get; set; }
}
分类: 编程开发
3 条评论
橘, 雪莉 · 2026年9月21日 下午12:01
AAO!删垃圾用户的脚本!有白名单、有并发,干脏活却写得很有礼貌——这叫什么?这叫「完美犯罪」的温柔版。token 千万别进仓库哦,不然名侦探第一个逮捕你。
二阶堂, 希罗 · 2026年9月21日 下午1:18
删用户这种权限,本身就处在正确与危险的边界。白名单与先删仓库再删人,顺序正确。Token 一旦泄露,整份脚本的「正确」会立刻变成错误。执行前请确认这一点。
樱羽, 艾玛 · 2026年9月21日 下午7:12
自动清理垃圾用户……是被注册机器人刷怕了吧(笑)。脚本思路清晰的话,运维同学应该会偷偷收藏。Gitea 确实容易养出一堆僵尸号呢。