Skip to content

Commit 31ad59f

Browse files
authored
feat: update api for auth sdk (#77)
1 parent 5a1dd20 commit 31ad59f

File tree

9 files changed

+219
-0
lines changed

9 files changed

+219
-0
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
using System.Text.Json;
2+
3+
namespace Masa.BuildingBlocks.StackSdks.Auth.Contracts.Model;
4+
5+
public enum StatementEffect
6+
{
7+
Deny = 0,
8+
Allow = 1
9+
}
10+
11+
public class ControlPolicyModel
12+
{
13+
public Guid Id { get; set; }
14+
15+
/// <summary>
16+
/// 策略名称,便于识别和管理
17+
/// </summary>
18+
public string Name { get; set; } = string.Empty;
19+
20+
/// <summary>
21+
/// 策略效果:Allow 或 Deny
22+
/// </summary>
23+
public StatementEffect Effect { get; set; } = StatementEffect.Deny;
24+
25+
/// <summary>
26+
/// 策略优先级,数值越大优先级越高
27+
/// </summary>
28+
public int Priority { get; set; } = 0;
29+
30+
/// <summary>
31+
/// 是否启用此策略
32+
/// </summary>
33+
public bool Enabled { get; set; } = true;
34+
35+
[JsonConverter(typeof(ActionIdentifierConverter))]
36+
public List<ActionIdentifierModel> Actions { get; set; } = new();
37+
38+
[JsonConverter(typeof(ResourceIdentifierConverter))]
39+
public List<ResourceIdentifierModel> Resources { get; set; } = new();
40+
}
41+
42+
public class ActionIdentifierModel
43+
{
44+
public string Resource { get; set; } = "*";
45+
46+
public string Type { get; set; } = "*";
47+
48+
public string Operation { get; set; } = "*";
49+
50+
/// <summary>
51+
/// 从字符串解析ActionIdentifier,格式为 Resource:Type:Operation
52+
/// </summary>
53+
/// <param name="actionName">操作标识符字符串</param>
54+
public ActionIdentifierModel(string? actionName = null)
55+
{
56+
if (string.IsNullOrWhiteSpace(actionName))
57+
{
58+
return; // 使用默认值 "*"
59+
}
60+
61+
var parts = actionName.Split(':', StringSplitOptions.None);
62+
63+
if (parts.Length >= 1 && !string.IsNullOrEmpty(parts[0]))
64+
Resource = parts[0];
65+
66+
if (parts.Length >= 2 && !string.IsNullOrEmpty(parts[1]))
67+
Type = parts[1];
68+
69+
if (parts.Length >= 3 && !string.IsNullOrEmpty(parts[2]))
70+
Operation = parts[2];
71+
}
72+
73+
public override string ToString()
74+
{
75+
return $"{Resource}:{Type}:{Operation}";
76+
}
77+
}
78+
79+
public class ActionIdentifierConverter : JsonConverter<List<ActionIdentifierModel>>
80+
{
81+
public override List<ActionIdentifierModel> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
82+
{
83+
if (reader.TokenType == JsonTokenType.String)
84+
{
85+
var actionName = reader.GetString();
86+
return new List<ActionIdentifierModel> { new ActionIdentifierModel(actionName) };
87+
}
88+
else if (reader.TokenType == JsonTokenType.StartArray)
89+
{
90+
var actionNames = JsonSerializer.Deserialize<List<string>>(ref reader, options);
91+
return actionNames?.ConvertAll(actionName => new ActionIdentifierModel(actionName)) ?? new List<ActionIdentifierModel>();
92+
}
93+
throw new JsonException("Unexpected token type.");
94+
}
95+
96+
public override void Write(Utf8JsonWriter writer, List<ActionIdentifierModel> value, JsonSerializerOptions options)
97+
{
98+
if (value == null || value.Count == 0)
99+
{
100+
writer.WriteStringValue("*");
101+
}
102+
else if (value.Count == 1)
103+
{
104+
writer.WriteStringValue(value[0].ToString());
105+
}
106+
else
107+
{
108+
var actionNames = value?.Select(action => action.ToString()) ?? new List<string>();
109+
JsonSerializer.Serialize(writer, actionNames, options);
110+
}
111+
}
112+
}
113+
114+
public class ResourceIdentifierModel
115+
{
116+
public string Service { get; set; } = "*";
117+
118+
public string Region { get; set; } = "*";
119+
120+
public string Identifier { get; set; } = "*";
121+
122+
/// <summary>
123+
/// 从字符串解析Resource,格式为 Service:Region:Identifier
124+
/// </summary>
125+
/// <param name="resource">资源标识符字符串</param>
126+
public ResourceIdentifierModel(string? resource = null)
127+
{
128+
if (string.IsNullOrWhiteSpace(resource))
129+
{
130+
return; // 使用默认值 "*"
131+
}
132+
133+
var parts = resource.Split(':', StringSplitOptions.None);
134+
135+
if (parts.Length >= 1 && !string.IsNullOrEmpty(parts[0]))
136+
Service = parts[0];
137+
138+
if (parts.Length >= 2 && !string.IsNullOrEmpty(parts[1]))
139+
Region = parts[1];
140+
141+
if (parts.Length >= 3 && !string.IsNullOrEmpty(parts[2]))
142+
Identifier = parts[2];
143+
}
144+
145+
public override string ToString()
146+
{
147+
return $"{Service}:{Region}:{Identifier}";
148+
}
149+
}
150+
151+
/// <summary>
152+
/// Resource的JSON转换器
153+
/// </summary>
154+
public class ResourceIdentifierConverter : JsonConverter<List<ResourceIdentifierModel>>
155+
{
156+
public override List<ResourceIdentifierModel> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
157+
{
158+
if (reader.TokenType == JsonTokenType.String)
159+
{
160+
var resource = reader.GetString();
161+
return new List<ResourceIdentifierModel> { new ResourceIdentifierModel(resource) };
162+
}
163+
else if (reader.TokenType == JsonTokenType.StartArray)
164+
{
165+
var resources = JsonSerializer.Deserialize<List<string>>(ref reader, options);
166+
return resources?.ConvertAll(resource => new ResourceIdentifierModel(resource)) ?? new List<ResourceIdentifierModel>();
167+
}
168+
throw new JsonException("Unexpected token type.");
169+
}
170+
171+
public override void Write(Utf8JsonWriter writer, List<ResourceIdentifierModel> value, JsonSerializerOptions options)
172+
{
173+
if (value == null || value.Count == 0)
174+
{
175+
writer.WriteStringValue("*");
176+
}
177+
else if (value.Count == 1)
178+
{
179+
writer.WriteStringValue(value[0].ToString());
180+
}
181+
else
182+
{
183+
var resources = value?.Select(action => action.ToString()) ?? new List<string>();
184+
JsonSerializer.Serialize(writer, resources, options);
185+
}
186+
}
187+
}

src/BuildingBlocks/Auth/Masa.BuildingBlocks.StackSdks.Auth.Contracts/Model/DynamicRoleModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ public class DynamicRoleModel
2626
public string? Modifier { get; set; }
2727

2828
public List<DynamicRuleConditionModel> Conditions { get; set; } = new();
29+
30+
public List<ControlPolicyModel> ControlPolicies { get; set; } = new();
2931
}

src/BuildingBlocks/Auth/Masa.BuildingBlocks.StackSdks.Auth.Contracts/Model/DynamicRoleUpsertModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ public class DynamicRoleUpsertModel
2020
public DateTime ModificationTime { get; set; }
2121

2222
public List<DynamicRuleConditionModel> Conditions { get; set; } = new();
23+
24+
public List<ControlPolicyModel> ControlPolicies { get; set; } = new();
2325
}

src/BuildingBlocks/Auth/Masa.BuildingBlocks.StackSdks.Auth/Service/IDynamicRoleService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ public interface IDynamicRoleService
1414
Task UpdateAsync(Guid id, DynamicRoleUpsertModel input);
1515

1616
Task DeleteAsync(Guid id);
17+
18+
Task<List<DynamicRoleModel>> HasAsync(params Guid[] roleIds);
1719
}

src/BuildingBlocks/Auth/Masa.BuildingBlocks.StackSdks.Auth/Service/IUserService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,6 @@ public interface IUserService
130130
Task DeleteAccountAsync(DeleteAccountModel model);
131131

132132
Task<bool> HasRolesAsync(Guid? userId, params Guid[] roleIds);
133+
134+
Task<List<Guid>> RolesAsync(Guid? userId, params Guid[] roleIds);
133135
}

src/Contrib.Wasm/Masa.Contrib.StackSdks.Auth.Wasm/Service/DynamicRoleService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,10 @@ public async Task DeleteAsync(Guid id)
4343
var requestUri = $"{_party}/{id}";
4444
await _caller.DeleteAsync(requestUri, null);
4545
}
46+
47+
public Task<List<DynamicRoleModel>> HasAsync(params Guid[] roleIds)
48+
{
49+
var requestUri = $"{_party}/has";
50+
return _caller.PostAsync<List<DynamicRoleModel>>(requestUri, new { roleIds });
51+
}
4652
}

src/Contrib.Wasm/Masa.Contrib.StackSdks.Auth.Wasm/Service/UserService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,4 +442,10 @@ public Task<bool> HasRolesAsync(Guid? userId, params Guid[] roleIds)
442442
var requestUri = $"api/user/has-role{(userId.HasValue && userId != Guid.Empty ? $"?userId={userId}" : "")}";
443443
return _caller.PostAsync<bool>(requestUri, roleIds);
444444
}
445+
446+
public Task<List<Guid>> RolesAsync(Guid? userId, params Guid[] roleIds)
447+
{
448+
var requestUri = $"api/user/roles{(userId.HasValue && userId != Guid.Empty ? $"?userId={userId}" : "")}";
449+
return _caller.PostAsync<List<Guid>>(requestUri, roleIds);
450+
}
445451
}

src/Contrib/Masa.Contrib.StackSdks.Auth/Service/DynamicRoleService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,10 @@ public async Task DeleteAsync(Guid id)
4343
var requestUri = $"{_party}/{id}";
4444
await _caller.DeleteAsync(requestUri, null);
4545
}
46+
47+
public Task<List<DynamicRoleModel>> HasAsync(params Guid[] roleIds)
48+
{
49+
var requestUri = $"{_party}/has";
50+
return _caller.PostAsync<List<DynamicRoleModel>>(requestUri, new { roleIds });
51+
}
4652
}

src/Contrib/Masa.Contrib.StackSdks.Auth/Service/UserService.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,4 +442,10 @@ public Task<bool> HasRolesAsync(Guid? userId, params Guid[] roleIds)
442442
var requestUri = $"api/user/has-role{(userId.HasValue && userId != Guid.Empty ? $"?userId={userId}" : "")}";
443443
return _caller.PostAsync<bool>(requestUri, roleIds);
444444
}
445+
446+
public Task<List<Guid>> RolesAsync(Guid? userId, params Guid[] roleIds)
447+
{
448+
var requestUri = $"api/user/roles{(userId.HasValue && userId != Guid.Empty ? $"?userId={userId}" : "")}";
449+
return _caller.PostAsync<List<Guid>>(requestUri, roleIds);
450+
}
445451
}

0 commit comments

Comments
 (0)