Skip to content

Commit 9d0fe65

Browse files
feat: support sharing stats
by generating a jwt and including it in the link
1 parent 0676cb2 commit 9d0fe65

22 files changed

Lines changed: 356 additions & 32 deletions

File tree

HwProj.APIGateway/HwProj.APIGateway.API/Controllers/AccountController.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,15 @@ public async Task<IActionResult> RefreshToken()
121121
var tokenMeta = await AuthServiceClient.RefreshToken(UserId!);
122122
return Ok(tokenMeta);
123123
}
124+
125+
[HttpGet("getGuestToken")]
126+
[Authorize(Roles = Roles.LecturerRole)]
127+
[ProducesResponseType(typeof(TokenCredentials), (int)HttpStatusCode.OK)]
128+
public async Task<IActionResult> GetGuestToken([FromQuery] string courseId)
129+
{
130+
var tokenMeta = await AuthServiceClient.GetGuestToken(courseId);
131+
return Ok(tokenMeta);
132+
}
124133

125134
[HttpPut("edit")]
126135
[Authorize]

HwProj.APIGateway/HwProj.APIGateway.API/Controllers/StatisticsController.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Linq;
1+
using System;
2+
using System.Linq;
23
using System.Net;
34
using System.Threading.Tasks;
45
using HwProj.APIGateway.API.Models.Statistics;
@@ -7,6 +8,7 @@
78
using HwProj.Models.CoursesService.ViewModels;
89
using HwProj.Models.Roles;
910
using HwProj.SolutionsService.Client;
11+
using HwProj.Utils.Auth;
1012
using Microsoft.AspNetCore.Authorization;
1113
using Microsoft.AspNetCore.Mvc;
1214

@@ -70,14 +72,16 @@ public async Task<IActionResult> GetCourseStatistics(long courseId)
7072
}
7173

7274
[HttpGet("{courseId}/charts")]
75+
[Authorize(AuthenticationSchemes = AuthSchemeConstants.QueryStringTokenOrDefaultAuthentication)]
7376
[ProducesResponseType(typeof(AdvancedCourseStatisticsViewModel), (int)HttpStatusCode.OK)]
74-
public async Task<IActionResult> GetChartStatistics(long courseId)
77+
public async Task<IActionResult> GetChartStatistics(long courseId, [FromQuery] string token)
7578
{
7679
var course = await _coursesClient.GetCourseById(courseId);
7780
if (course == null)
7881
return Forbid();
7982

8083
var statistics = await _solutionClient.GetCourseStatistics(courseId, UserId);
84+
8185
var studentIds = statistics.Select(t => t.StudentId).ToArray();
8286
var studentsData = await AuthServiceClient.GetAccountsData(studentIds);
8387

HwProj.APIGateway/HwProj.APIGateway.API/Startup.cs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
using HwProj.AuthService.Client;
1+
using System;
2+
using System.Threading.Tasks;
3+
using HwProj.AuthService.Client;
24
using HwProj.CoursesService.Client;
35
using HwProj.NotificationsService.Client;
46
using HwProj.SolutionsService.Client;
57
using HwProj.Utils.Auth;
68
using HwProj.Utils.Configuration;
9+
using Microsoft.AspNetCore.Authentication.JwtBearer;
710
using Microsoft.AspNetCore.Builder;
811
using Microsoft.AspNetCore.Hosting;
912
using Microsoft.Extensions.Configuration;
@@ -27,7 +30,10 @@ public void ConfigureServices(IServiceCollection services)
2730

2831
const string authenticationProviderKey = "GatewayKey";
2932

30-
services.AddAuthentication()
33+
services.AddAuthentication(options =>
34+
{
35+
options.DefaultScheme = authenticationProviderKey;
36+
})
3137
.AddJwtBearer(authenticationProviderKey, x =>
3238
{
3339
x.RequireHttpsMetadata = false;
@@ -40,6 +46,55 @@ public void ConfigureServices(IServiceCollection services)
4046
IssuerSigningKey = AuthorizationKey.SecurityKey,
4147
ValidateIssuerSigningKey = true
4248
};
49+
})
50+
.AddJwtBearer(AuthSchemeConstants.QueryStringTokenAuthentication, options =>
51+
{
52+
options.RequireHttpsMetadata = false;
53+
options.TokenValidationParameters = new TokenValidationParameters
54+
{
55+
ValidateIssuer = true,
56+
ValidIssuer = "AuthService",
57+
ValidateLifetime = false,
58+
ValidateAudience = false,
59+
IssuerSigningKey = AuthorizationKey.SecurityKey
60+
};
61+
62+
options.Events = new JwtBearerEvents
63+
{
64+
OnMessageReceived = context =>
65+
{
66+
if (context.Request.Query.ContainsKey("token"))
67+
{
68+
context.Token = context.Request.Query["token"];
69+
}
70+
else
71+
{
72+
context.Fail("Unauthorized");
73+
}
74+
75+
return Task.CompletedTask;
76+
},
77+
OnTokenValidated = async context =>
78+
{
79+
var courseIdClaim = context.Principal.FindFirst("_courseId");
80+
if (courseIdClaim == null)
81+
{
82+
context.Fail("Unauthorized");
83+
return;
84+
}
85+
86+
var authServiceClient = context.HttpContext.RequestServices
87+
.GetRequiredService<IAuthServiceClient>();
88+
var statsAccessToken = await authServiceClient.GetGuestToken(courseIdClaim.Value);
89+
var guestToken = context.Request.Query["token"];
90+
91+
if (statsAccessToken.AccessToken != guestToken)
92+
{
93+
context.Fail("Unauthorized");
94+
}
95+
}
96+
};
97+
4398
});
4499

45100
services.AddHttpClient();

HwProj.AuthService/HwProj.AuthService.API/Controllers/AccountController.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ public async Task<IActionResult> RefreshToken(string userId)
8282
var tokenMeta = await _accountService.RefreshToken(userId);
8383
return Ok(tokenMeta);
8484
}
85+
86+
[HttpGet("getGuestToken")]
87+
[ProducesResponseType(typeof(TokenCredentials), (int)HttpStatusCode.OK)]
88+
public async Task<TokenCredentials> GetGuestToken([FromQuery] string courseId)
89+
{
90+
var tokenMeta = await _accountService.GetGuestToken(courseId);
91+
return tokenMeta;
92+
}
8593

8694
[HttpPut("edit/{userId}")]
8795
[ProducesResponseType(typeof(Result), (int)HttpStatusCode.OK)]

HwProj.AuthService/HwProj.AuthService.API/Services/AccountService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ public async Task<Result<TokenCredentials>> RefreshToken(string userId)
136136
? Result<TokenCredentials>.Failed("Пользователь не найден")
137137
: await GetToken(user);
138138
}
139+
140+
public async Task<TokenCredentials> GetGuestToken(string courseId)
141+
{
142+
return await _tokenService.GetTokenAsync(courseId);
143+
}
139144

140145
public async Task<Result<TokenCredentials>> RegisterUserAsync(RegisterDataDTO model)
141146
{

HwProj.AuthService/HwProj.AuthService.API/Services/AuthTokenService.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,26 @@ public async Task<TokenCredentials> GetTokenAsync(User user)
5151

5252
return tokenCredentials;
5353
}
54+
55+
public async Task<TokenCredentials> GetTokenAsync(string courseId)
56+
{
57+
var securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration["SecurityKey"]));
58+
59+
var token = new JwtSecurityToken(
60+
issuer: _configuration["ApiName"],
61+
claims: new[]
62+
{
63+
new Claim("_courseId", courseId),
64+
new Claim("_isGuest", "true")
65+
},
66+
signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256));
67+
68+
var tokenCredentials = new TokenCredentials
69+
{
70+
AccessToken = new JwtSecurityTokenHandler().WriteToken(token)
71+
};
72+
73+
return tokenCredentials;
74+
}
5475
}
5576
}

HwProj.AuthService/HwProj.AuthService.API/Services/IAccountService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public interface IAccountService
1616
Task<Result> EditAccountAsync(string accountId, EditDataDTO model);
1717
Task<Result<TokenCredentials>> LoginUserAsync(LoginViewModel model);
1818
Task<Result<TokenCredentials>> RefreshToken(string userId);
19+
Task<TokenCredentials> GetGuestToken(string courseId);
1920
Task<Result> InviteNewLecturer(string emailOfInvitedUser);
2021
Task<IList<User>> GetUsersInRole(string role);
2122
Task<Result> RequestPasswordRecovery(RequestPasswordRecoveryViewModel model);

HwProj.AuthService/HwProj.AuthService.API/Services/IAuthTokenService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ namespace HwProj.AuthService.API.Services
77
public interface IAuthTokenService
88
{
99
Task<TokenCredentials> GetTokenAsync(User user);
10+
Task<TokenCredentials> GetTokenAsync(string courseId);
1011
}
1112
}

HwProj.AuthService/HwProj.AuthService.Client/AuthServiceClient.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,16 @@ public async Task<Result<TokenCredentials>> RefreshToken(string userId)
9999
var response = await _httpClient.SendAsync(httpRequest);
100100
return await response.DeserializeAsync<Result<TokenCredentials>>();
101101
}
102+
103+
public async Task<TokenCredentials> GetGuestToken(string courseId)
104+
{
105+
using var httpRequest = new HttpRequestMessage(
106+
HttpMethod.Get,
107+
_authServiceUri + $"api/account/getGuestToken/?courseId={courseId}");
108+
109+
var response = await _httpClient.SendAsync(httpRequest);
110+
return await response.DeserializeAsync<TokenCredentials>();
111+
}
102112

103113
public async Task<Result> Edit(EditAccountViewModel model, string userId)
104114
{

HwProj.AuthService/HwProj.AuthService.Client/IAuthServiceClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public interface IAuthServiceClient
1313
Task<Result<TokenCredentials>> Register(RegisterViewModel model);
1414
Task<Result<TokenCredentials>> Login(LoginViewModel model);
1515
Task<Result<TokenCredentials>> RefreshToken(string userId);
16+
Task<TokenCredentials> GetGuestToken(string courseId);
1617
Task<Result> Edit(EditAccountViewModel model, string userId);
1718
Task<Result> InviteNewLecturer(InviteLecturerViewModel model);
1819
Task<Result> EditExternal(EditExternalViewModel model, string userId);

0 commit comments

Comments
 (0)