diff --git a/HanyadikHetVan/Controllers/V1/TestController.cs b/HanyadikHetVan/Controllers/V1/TestController.cs index a598bf9..f4a0567 100644 --- a/HanyadikHetVan/Controllers/V1/TestController.cs +++ b/HanyadikHetVan/Controllers/V1/TestController.cs @@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authentication.JwtBearer; using System; -using System.Data; using System.Net.Mime; using System.Security.Claims; @@ -34,10 +34,10 @@ namespace HanyadikHetVan.Controllers.V1 [Produces(MediaTypeNames.Application.Json)] public string Protected() { - return this.User.FindFirst(ClaimTypes.Role).Value; + return this.User.FindFirst("user_role").Value; } - [Authorize(Roles = "admin")] + [Authorize(Policy = "AdminPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [HttpGet("roleprotected")] [Produces(MediaTypeNames.Application.Json)] public string RoleProtected() diff --git a/HanyadikHetVan/Controllers/V2/FunFactController.cs b/HanyadikHetVan/Controllers/V2/FunFactController.cs index d915862..de9d8c9 100644 --- a/HanyadikHetVan/Controllers/V2/FunFactController.cs +++ b/HanyadikHetVan/Controllers/V2/FunFactController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; +using System.Collections.Generic; using System.Threading.Tasks; namespace HanyadikHetVan.Controllers.V2 @@ -20,8 +21,8 @@ namespace HanyadikHetVan.Controllers.V2 _funfactService = funfactService ?? throw new ArgumentNullException(nameof(funfactService)); } - [HttpPut("{weeklytimespanId}")] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(FunFactDTO))] + [HttpGet("WeeklyTimeSpan/{weeklytimespanId}")] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List))] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetFunFactOfWeeklyTimeSpan(int weeklytimespanId) { diff --git a/HanyadikHetVan/Controllers/V2/PauseController.cs b/HanyadikHetVan/Controllers/V2/PauseController.cs index 088b030..9c9af19 100644 --- a/HanyadikHetVan/Controllers/V2/PauseController.cs +++ b/HanyadikHetVan/Controllers/V2/PauseController.cs @@ -1,5 +1,6 @@ using HanyadikHetVan.DTO; using HanyadikHetVan.Services; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -41,7 +42,7 @@ namespace HanyadikHetVan.Controllers.V2 } } [HttpDelete("{pauseId}")] - [Authorize(Roles = "admin")] + [Authorize(Policy = "AdminPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(WeeklyTimeSpanDTO))] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] @@ -58,7 +59,7 @@ namespace HanyadikHetVan.Controllers.V2 } } [HttpPut] - [Authorize(Roles = "admin")] + [Authorize(Policy = "AdminPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [Consumes(MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(PauseDTO))] [ProducesResponseType(StatusCodes.Status404NotFound)] diff --git a/HanyadikHetVan/Controllers/V2/WeeklyTimeSpanController.cs b/HanyadikHetVan/Controllers/V2/WeeklyTimeSpanController.cs index d43f0b9..059213e 100644 --- a/HanyadikHetVan/Controllers/V2/WeeklyTimeSpanController.cs +++ b/HanyadikHetVan/Controllers/V2/WeeklyTimeSpanController.cs @@ -1,6 +1,7 @@ using HanyadikHetVan.Data.Entities; using HanyadikHetVan.DTO; using HanyadikHetVan.Services; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; @@ -46,7 +47,7 @@ namespace HanyadikHetVan.Controllers.V2 } } [HttpDelete("{weeklyTimeSpanId}")] - [Authorize(Roles = "admin")] + [Authorize(Policy = "AdminPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(bool))] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] @@ -63,7 +64,7 @@ namespace HanyadikHetVan.Controllers.V2 } } [HttpPut] - [Authorize(Roles = "admin")] + [Authorize(Policy = "AdminPolicy", AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [Consumes(MediaTypeNames.Application.Json)] [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(WeeklyTimeSpanDTO))] [ProducesResponseType(StatusCodes.Status404NotFound)] diff --git a/HanyadikHetVan/Infrastructure/EmailSender.cs b/HanyadikHetVan/Infrastructure/EmailSender.cs new file mode 100644 index 0000000..698995a --- /dev/null +++ b/HanyadikHetVan/Infrastructure/EmailSender.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Identity.UI.Services; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Mail; +using System.Threading.Tasks; + +namespace HanyadikHetVan.Infrastructure +{ + public class EmailSender : IEmailSender + { + private readonly EmailSenderConfig _emailsenderconfig; + + public EmailSender(IOptions emailsenderconfig) + { + _emailsenderconfig = emailsenderconfig.Value; + } + + public Task SendEmailAsync(string email, string subject, string htmlMessage) + { + + + var client = new SmtpClient(_emailsenderconfig.Host, _emailsenderconfig.Port) + { + UseDefaultCredentials = false, + EnableSsl = false + }; + return client.SendMailAsync( + new MailMessage(_emailsenderconfig.UserName, email, subject, htmlMessage) { IsBodyHtml = true } + ); + } + } +} diff --git a/HanyadikHetVan/Infrastructure/EmailSenderConfig.cs b/HanyadikHetVan/Infrastructure/EmailSenderConfig.cs new file mode 100644 index 0000000..ff98328 --- /dev/null +++ b/HanyadikHetVan/Infrastructure/EmailSenderConfig.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace HanyadikHetVan.Infrastructure +{ + public class EmailSenderConfig + { + public string Host { get; set; } + public int Port { get; set; } + public string UserName { get; set; } + } +} diff --git a/HanyadikHetVan/Infrastructure/ProfileService.cs b/HanyadikHetVan/Infrastructure/ProfileService.cs index cfd8568..21c4e55 100644 --- a/HanyadikHetVan/Infrastructure/ProfileService.cs +++ b/HanyadikHetVan/Infrastructure/ProfileService.cs @@ -2,6 +2,8 @@ using IdentityServer4.Models; using IdentityServer4.Services; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Logging; +using System; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; @@ -11,10 +13,12 @@ namespace HanyadikHetVan.Infrastructure public class ProfileService : IProfileService { private readonly UserManager userManager; + private readonly ILogger _logger; - public ProfileService(UserManager userManager) + public ProfileService(UserManager userManager, ILogger logger) { this.userManager = userManager; + this._logger = logger; } public async Task GetProfileDataAsync(ProfileDataRequestContext context) diff --git a/HanyadikHetVan/Services/FunFactService.cs b/HanyadikHetVan/Services/FunFactService.cs index 340cedd..12f954e 100644 --- a/HanyadikHetVan/Services/FunFactService.cs +++ b/HanyadikHetVan/Services/FunFactService.cs @@ -4,6 +4,7 @@ using HanyadikHetVan.Data.Entities; using HanyadikHetVan.DTO; using Microsoft.EntityFrameworkCore; using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -20,10 +21,10 @@ namespace HanyadikHetVan.Services _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } - public async Task GetFunFactOfWeeklyTimeSpan(int weeklytimespanId) + public async Task> GetFunFactOfWeeklyTimeSpan(int weeklytimespanId) { - var funfact = await _dbContext.FunFacts.Where(x => x.WeeklyTimeSpanId == weeklytimespanId).FirstOrDefaultAsync(); - return _mapper.Map(funfact); + var funfact = await _dbContext.FunFacts.Where(x => x.WeeklyTimeSpanId == weeklytimespanId).ToListAsync(); + return _mapper.Map, List>(funfact); } public async Task GetFunFactorOfFunFact(int funfactId) diff --git a/HanyadikHetVan/Startup.cs b/HanyadikHetVan/Startup.cs index b4b9b81..3497af7 100644 --- a/HanyadikHetVan/Startup.cs +++ b/HanyadikHetVan/Startup.cs @@ -7,11 +7,16 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; using System.Reflection; namespace HanyadikHetVan @@ -39,6 +44,8 @@ namespace HanyadikHetVan services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.Configure(Configuration.GetSection("EmailSender")); services.AddDatabaseDeveloperPageExceptionFilter(); services.AddAuthentication(config => @@ -50,26 +57,46 @@ namespace HanyadikHetVan config.Authority = "https://localhost:5001"; config.Audience = "api"; config.RequireHttpsMetadata = false; + config.TokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = false, + ValidateAudience = true, + ValidateIssuerSigningKey = false, + RequireSignedTokens = false, + SignatureValidator = delegate (string token, TokenValidationParameters parameters) + { + return new JwtSecurityToken(token); + }, + ValidateLifetime = false, + RequireExpirationTime = false + }; }); services.AddAuthorization(config => { config.AddPolicy("default", config => config.RequireAuthenticatedUser().AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)); config.DefaultPolicy = config.GetPolicy("default"); + config.AddPolicy("AdminPolicy", p => p.RequireClaim("user_role", "admin")); }); - services.AddIdentity(options => options.SignIn.RequireConfirmedAccount = true) + services.AddIdentity(options => { options.SignIn.RequireConfirmedAccount = true; }) .AddDefaultTokenProviders() .AddEntityFrameworkStores(); - services.AddIdentityServer() + services.AddIdentityServer(o => + { + o.UserInteraction.LoginUrl = "/Identity/Account/Login"; + o.UserInteraction.LogoutUrl = "/Identity/Account/Logout"; + o.UserInteraction.ErrorUrl = "/Identity/Account/Error"; + }) .AddDeveloperSigningCredential() .AddInMemoryPersistedGrants() .AddInMemoryIdentityResources(Configuration.GetSection("IdentityServer:IdentityResources")) .AddInMemoryApiResources(Configuration.GetSection("IdentityServer:ApiResources")) .AddInMemoryApiScopes(Configuration.GetSection("IdentityServer:ApiScopes")) .AddInMemoryClients(Configuration.GetSection("IdentityServer:Clients")) - .AddAspNetIdentity(); + .AddAspNetIdentity() + .AddProfileService(); services.AddRazorPages(); @@ -88,6 +115,25 @@ namespace HanyadikHetVan services.AddSwaggerGen(c => { + c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows + { + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri("https://localhost:5001/connect/authorize"), + TokenUrl = new Uri("https://localhost:5001/connect/token"), + Scopes = new Dictionary + { + {"profile", "Profile"}, + {"openid", "OpenID"}, + {"user_role", "User roles"}, + {"api.readwrite", "Access to api"} + } + } + } + }); c.SwaggerDoc("v1", new OpenApiInfo { Title = "Hanyadik Het Van API", Version = "v1" }); c.SwaggerDoc("v2", new OpenApiInfo { Title = "Hanyadik Het Van API", Version = "v2" }); }); @@ -101,10 +147,10 @@ namespace HanyadikHetVan app.UseMigrationsEndPoint(); app.UseSwagger(); app.UseSwaggerUI(c => - { - c.SwaggerEndpoint("v1/swagger.json", "Original API"); - c.SwaggerEndpoint("v2/swagger.json", "Homework API"); - }); + { + c.SwaggerEndpoint("v1/swagger.json", "Original API"); + c.SwaggerEndpoint("v2/swagger.json", "Homework API"); + }); } else { diff --git a/HanyadikHetVan/appsettings.json b/HanyadikHetVan/appsettings.json index e6d62f7..54174b4 100644 --- a/HanyadikHetVan/appsettings.json +++ b/HanyadikHetVan/appsettings.json @@ -1,23 +1,21 @@ { + "AllowedHosts": "*", "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-HanyadikHetVan-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true" }, - "HanyadikHetVan": { - "StartDate": "2021-02-01" - }, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, "DefaultAdministrator": { "UserName": "testuser", "Email": "admin@teszt.hu", "Password": "Alma123." }, - "AllowedHosts": "*", + "EmailSender": { + "Host": "192.168.42.7", + "Port": 25, + "UserName": "hanyadikhetvan@kmlabz.com" + }, + "HanyadikHetVan": { + "StartDate": "2021-02-01" + }, "IdentityServer": { "IdentityResources": [ { @@ -64,8 +62,43 @@ "profile", "user_role", "api.readwrite" - ] + ], + "AlwaysIncludeUserClaimsInIdToken": true + }, + { + "ClientId": "swagger", + "ClientName": "Swagger client", + "AllowedGrantTypes": [ "authorization_code" ], + "AllowAccessTokensViaBrowser": true, + "ClientClaimsPrefix": "", + "RequireConsent": false, + "AllowedScopes": [ + "openid", + "profile", + "user_role", + "api.readwrite" + ], + "RedirectUris": [ + "http://localhost:5000/swagger/oauth2-redirect.html", + "https://localhost:5001/swagger/oauth2-redirect.html" + ], + "PostLogoutRedirectUris": [ "https://localhost:5001/swagger" ], + "AllowedCorsOrigins": [ "https://localhost:5001" ], + "AlwaysIncludeUserClaimsInIdToken": true, + "AllowOfflineAccess": true, + "EnableLocalLogin": true, + "IdentityTokenLifetime": 1800, + "AccessTokenLifetime": 1800, + "RequireClientSecret": false, + "RequirePkce": false } ] + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } } }