Skip to content

Commit 3547c48

Browse files
committed
Changed the authorize attribute to take a list of Role enums instead of a string
1 parent 3e32456 commit 3547c48

File tree

9 files changed

+63
-29
lines changed

9 files changed

+63
-29
lines changed

.editorconfig

+3
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ indent_size = 2
1212
[*.cs]
1313
indent_style = space
1414
indent_size = 4
15+
16+
[*.{ts, tsx, js}]
17+
quote_type = single

.vscode/launch.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@
1515
"cwd": "${workspaceFolder}/src/WebServer",
1616
"stopAtEntry": false,
1717
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
18-
"serverReadyAction": {
19-
"action": "openExternally",
20-
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
21-
},
18+
// "serverReadyAction": {
19+
// "action": "openExternally",
20+
// "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
21+
// },
2222
"env": {
2323
"ASPNETCORE_ENVIRONMENT": "Development"
2424
},
@@ -29,7 +29,7 @@
2929
{
3030
"name": ".NET Core Attach",
3131
"type": "coreclr",
32-
"request": "attach"
32+
"request": "attach",
3333
}
3434
]
3535
}

src/WebServer/Auth/AuthorizeAttribute.cs

+12-14
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
using Microsoft.AspNetCore.Mvc.Filters;
66
using Serilog;
77
using WebServer.Model.Auth;
8-
using JsonSerializer = System.Text.Json.JsonSerializer;
98

109
namespace WebServer.Auth;
1110

1211
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
1312
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
1413
{
15-
public string Roles { get; set; } = "";
14+
private readonly Role[] _roles;
15+
16+
public AuthorizeAttribute(params Role[] roles)
17+
{
18+
_roles = roles;
19+
}
1620

1721
public void OnAuthorization(AuthorizationFilterContext context)
1822
{
@@ -28,25 +32,19 @@ public void OnAuthorization(AuthorizationFilterContext context)
2832
return;
2933
}
3034

31-
var unauthorizedResult = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
32-
3335
var account = (Account?)context.HttpContext?.Items?[GlobalConstants.CONTEXT_ACCOUNT_KEY];
3436

35-
logger.Debug("Account: {Account}", JsonSerializer.Serialize(account));
36-
logger.Debug("Roles: {Roles}", Roles);
37-
3837
if (account == null)
3938
{
40-
context.Result = unauthorizedResult;
39+
context.Result = new JsonResult(new { message = "Unauthorized" }) { StatusCode = StatusCodes.Status401Unauthorized };
4140
return;
4241
}
4342

44-
if (string.IsNullOrWhiteSpace(Roles)) return;
45-
46-
var roleList = Roles.Split(",").Select(r => r.Trim().ToUpper());
47-
48-
if (roleList.All(role => account.Roles.Contains(role))) return;
43+
if (_roles.Length == 0 || _roles.Any(role => account.Roles.Contains(role.ToString().ToUpper())))
44+
{
45+
return;
46+
}
4947

50-
context.Result = unauthorizedResult;
48+
context.Result = new JsonResult(new { message = "Forbidden" }) { StatusCode = 403 };
5149
}
5250
}

src/WebServer/Controllers/AdminControllers/LoginWhitelistController.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace WebServer.Controllers.AdminControllers;
99

10-
[Authorize(Roles = nameof(Role.SUPER_ADMIN))]
10+
[Authorize(Role.SUPER_ADMIN)]
1111
[ApiController]
1212
[Route("api/admin/login-whitelist")]
1313
public class LoginWhitelistController : ControllerBase

src/WebServer/Controllers/AdminControllers/UserController.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace WebServer.Controllers.AdminControllers;
1010

11-
[Authorize(Roles = nameof(Role.SUPER_ADMIN))]
11+
[Authorize(Role.SUPER_ADMIN)]
1212
[ApiController]
1313
[Route("api/admin/user")]
1414
public class UserController : ControllerBase

src/WebServer/Controllers/ProtectedController.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using Microsoft.AspNetCore.Mvc;
22
using WebServer.Auth;
3+
using WebServer.Model.Auth;
34

45
namespace WebServer.Controllers;
56

67
[ApiController]
78
[Route("api/[controller]")]
8-
[Authorize(Roles = Roles.USER)]
9+
[Authorize(Role.USER)]
910
public class ProtectedController : ControllerBase
1011
{
1112
private readonly ILogger<ProtectedController> _logger;

src/WebServer/Controllers/WeatherForecastController.cs

+5-6
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ public WeatherForecastController(ILogger<WeatherForecastController> logger)
2323
public IEnumerable<WeatherForecast> Get()
2424
{
2525
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
26-
{
27-
Date = DateTime.Now.AddDays(index),
28-
TemperatureC = Random.Shared.Next(-20, 55),
29-
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
30-
})
31-
.ToArray();
26+
{
27+
Date = DateTime.Now.AddDays(index),
28+
TemperatureC = Random.Shared.Next(-20, 55),
29+
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
30+
}).ToArray();
3231
}
3332
}

src/client/src/logic/ProtectedApi.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import ApiResponse from '../model/ApiResponse'
2+
import ApiBase from './ApiBase'
3+
4+
export default class ProtectedApi extends ApiBase {
5+
async getProtectedTest(): Promise<ApiResponse<string | null>> {
6+
return await this.get<string>('protected/test')
7+
}
8+
}
+26-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,33 @@
1-
export default function Account() {
1+
import Button from '@mui/material/Button/Button'
2+
import { useState } from 'react'
3+
import ProtectedApi from '../../logic/ProtectedApi'
4+
5+
const api = new ProtectedApi()
6+
7+
export default function Account() {
8+
const [data, setData] = useState<string>('')
9+
10+
const getData = async () => {
11+
const res = await api.getProtectedTest()
12+
if (res.isError()) {
13+
console.log(res.exception?.toJson())
14+
return
15+
}
16+
17+
setData(res.data || '')
18+
}
19+
20+
const clear = () => {
21+
setData('')
22+
}
23+
224
return (
325
<>
426
<h1>Account</h1>
527
<p>This page requires authentication.</p>
28+
<Button variant="contained" onClick={getData}>Test protected endpoint</Button>&nbsp;
29+
<Button variant="contained" onClick={clear}>Clear</Button>
30+
<div>{data}</div>
631
</>
732
)
833
}

0 commit comments

Comments
 (0)