Chat funcional com login Microsoft.

This commit is contained in:
Ricardo Carneiro 2025-01-31 18:19:35 -03:00
parent 37de164c4d
commit 93ce4db4d7
11 changed files with 318 additions and 12 deletions

37
Chat.sln Normal file
View File

@ -0,0 +1,37 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.7.34031.279
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatMvc", "Chat\ChatMvc.csproj", "{E4FE7FF1-A6A7-4A40-A940-E32C0679FFB0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chat.Infra", "Chat.Infra\Chat.Infra.csproj", "{FE24AD1A-B5A7-4CD4-A4AF-B0E4DE3A0E53}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chat.Domain", "Chat.Domain\Chat.Domain.csproj", "{C3E28CA0-1BD6-4E09-ACC7-D7E32096F027}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E4FE7FF1-A6A7-4A40-A940-E32C0679FFB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E4FE7FF1-A6A7-4A40-A940-E32C0679FFB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4FE7FF1-A6A7-4A40-A940-E32C0679FFB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4FE7FF1-A6A7-4A40-A940-E32C0679FFB0}.Release|Any CPU.Build.0 = Release|Any CPU
{FE24AD1A-B5A7-4CD4-A4AF-B0E4DE3A0E53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE24AD1A-B5A7-4CD4-A4AF-B0E4DE3A0E53}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE24AD1A-B5A7-4CD4-A4AF-B0E4DE3A0E53}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE24AD1A-B5A7-4CD4-A4AF-B0E4DE3A0E53}.Release|Any CPU.Build.0 = Release|Any CPU
{C3E28CA0-1BD6-4E09-ACC7-D7E32096F027}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3E28CA0-1BD6-4E09-ACC7-D7E32096F027}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3E28CA0-1BD6-4E09-ACC7-D7E32096F027}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3E28CA0-1BD6-4E09-ACC7-D7E32096F027}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EC4AB36F-49CB-4819-ACA4-3A14CB1D9B50}
EndGlobalSection
EndGlobal

View File

@ -7,6 +7,8 @@ using System.Text.Json;
using Newtonsoft.Json; using Newtonsoft.Json;
using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using System.Linq;
using Microsoft.AspNetCore.Authentication;
namespace ChatMvc.Controllers namespace ChatMvc.Controllers
{ {
@ -27,6 +29,8 @@ namespace ChatMvc.Controllers
public IActionResult Index() public IActionResult Index()
{ {
var tokens = _antiforgery.GetAndStoreTokens(HttpContext); var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
var token = HttpContext.GetTokenAsync("access_token").Result;
ViewBag.Token = token;
return View(); return View();
} }
@ -41,9 +45,13 @@ namespace ChatMvc.Controllers
return BadRequest("Requisição inválida"); return BadRequest("Requisição inválida");
} }
var userId = User.Claims.FirstOrDefault(f => f.Type == "UserId").Value;
var name = User.Claims.FirstOrDefault(f => f.Type == "FirstName").Value;
var company = User.Claims.FirstOrDefault(f => f.Type == "CompanyName").Value;
var token = User.Claims.FirstOrDefault(f => f.Type == "TokenExternal").Value;
var client = _httpClientFactory.CreateClient(); var client = _httpClientFactory.CreateClient();
var baseUrl = _configuration["ExternalApiBaseUrl"]; var baseUrl = _configuration["ExternalApiBaseUrl"];
var token = Request.Headers["Authorization"].ToString();
client.DefaultRequestHeaders.Authorization = client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.Replace("Bearer ", "")); new AuthenticationHeaderValue("Bearer", token.Replace("Bearer ", ""));

View File

@ -0,0 +1,94 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using static System.Net.Mime.MediaTypeNames;
namespace ChatMvc.Controllers
{
[Authorize]
public class DocumentsController : Controller
{
private readonly HttpClient _httpClient;
public DocumentsController()
{
_httpClient = new HttpClient();
_httpClient.BaseAddress = new Uri("http://localhost:5020/");
}
public async Task<IActionResult> Index()
{
var token = User.Claims.FirstOrDefault(f => f.Type == "TokenExternal").Value;
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.Replace("Bearer ", ""));
var response = await _httpClient.GetAsync("Chat/texts");
if (response.IsSuccessStatusCode)
{
var texts = await response.Content.ReadFromJsonAsync<IEnumerable<TextResponse>>();
return View(texts);
}
return View(new List<TextResponse>());
}
public IActionResult New()
{
return View();
}
public async Task<IActionResult> Edit(string id)
{
var token = User.Claims.FirstOrDefault(f => f.Type == "TokenExternal").Value;
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.Replace("Bearer ", ""));
var response = await _httpClient.GetAsync(string.Format("chat/texts/id/{0}", id));
if (response.IsSuccessStatusCode)
{
var text = await response.Content.ReadFromJsonAsync<TextResponse>();
var request = new TextRequest()
{
Id = text.Id,
Title = text.Title,
Content = text.Content
};
return View("New", request);
}
return View("New");
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Save([FromForm] TextRequest request)
{
var token = User.Claims.FirstOrDefault(f => f.Type == "TokenExternal").Value;
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.Replace("Bearer ", ""));
var response = await _httpClient.PostAsJsonAsync("chat/savetext", request);
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
return View("Novo", request);
}
}
public class TextResponse
{
public string Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
public class TextRequest
{
public string? Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
}

View File

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Stripe; using Stripe;
using ChatMvc.Managers;
namespace ChatMvc.Controllers namespace ChatMvc.Controllers
{ {
@ -12,12 +13,14 @@ namespace ChatMvc.Controllers
{ {
private readonly ILogger<LoginController> logger; private readonly ILogger<LoginController> logger;
private readonly IHttpClientFactory httpClientFactory; private readonly IHttpClientFactory httpClientFactory;
private readonly TokenManager tokenManager;
private readonly StripeClient _stripeClient; private readonly StripeClient _stripeClient;
public LoginController(ILogger<LoginController> logger, IHttpClientFactory httpClientFactory) public LoginController(ILogger<LoginController> logger, IHttpClientFactory httpClientFactory, TokenManager tokenManager)
{ {
this.logger = logger; this.logger = logger;
this.httpClientFactory = httpClientFactory; this.httpClientFactory = httpClientFactory;
this.tokenManager = tokenManager;
} }
public IActionResult Index() public IActionResult Index()
@ -55,12 +58,17 @@ namespace ChatMvc.Controllers
if (HttpContext.User.FindFirst(ClaimTypes.GivenName) != null) if (HttpContext.User.FindFirst(ClaimTypes.GivenName) != null)
{ {
var token = await tokenManager.GetToken(emailExist, "Domvs iT", HttpContext.User.FindFirst(ClaimTypes.GivenName).Value);
claims = new List<Claim> claims = new List<Claim>
{ {
new Claim(ClaimTypes.Email, emailExist), new Claim(ClaimTypes.Email, emailExist),
new Claim("FirstName", HttpContext.User.FindFirst(ClaimTypes.GivenName).Value), new Claim("FirstName", HttpContext.User.FindFirst(ClaimTypes.GivenName).Value),
new Claim("FullName", HttpContext.User.FindFirst(ClaimTypes.GivenName).Value + " " + HttpContext.User.FindFirst(ClaimTypes.Surname).Value), new Claim("FullName", HttpContext.User.FindFirst(ClaimTypes.GivenName).Value + " " + HttpContext.User.FindFirst(ClaimTypes.Surname).Value),
new Claim(ClaimTypes.Role, "User"), new Claim("CompanyName", "Domvs iT"),
new Claim("UserId", emailExist),
new Claim("TokenExternal", token),
new Claim(ClaimTypes.Role, "User"),
}; };
} }
else if (HttpContext.User.FindFirst(ClaimTypes.Name)!=null) else if (HttpContext.User.FindFirst(ClaimTypes.Name)!=null)
@ -68,12 +76,17 @@ namespace ChatMvc.Controllers
var name = HttpContext.User.FindFirst(ClaimTypes.Name).Value; var name = HttpContext.User.FindFirst(ClaimTypes.Name).Value;
var firstName = name.Split(' ')[0]; var firstName = name.Split(' ')[0];
var token = await tokenManager.GetToken(emailExist, "Domvs iT", firstName);
claims = new List<Claim> claims = new List<Claim>
{ {
new Claim(ClaimTypes.Email, emailExist), new Claim(ClaimTypes.Email, emailExist),
new Claim("FirstName", firstName), new Claim("FirstName", firstName),
new Claim("FullName", name), new Claim("FullName", name),
new Claim(ClaimTypes.Role, "User"), new Claim("UserId", emailExist),
new Claim("CompanyName", "Domvs iT"),
new Claim("TokenExternal", token),
new Claim(ClaimTypes.Role, "User"),
}; };
} }

View File

@ -0,0 +1,63 @@
using ChatMvc.Controllers;
using Newtonsoft.Json;
using Stripe.Forwarding;
using System.Net.Http;
using System.Text;
namespace ChatMvc.Managers
{
public class TokenManager
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IConfiguration _configuration;
public TokenManager(IHttpClientFactory httpClientFactory, IConfiguration configuration)
{
this._httpClientFactory = httpClientFactory;
this._configuration = configuration;
}
public async Task<string> GetToken(string userId, string company, string name)
{
var client = _httpClientFactory.CreateClient();
var baseUrl = _configuration["ExternalApiBaseUrl"];
// Primeira requisição - newclient
var newClientRequest = new
{
localId = userId,
companyTenant = company,
name = name
};
var newClientResponse = await client.PostAsync(
$"{baseUrl}/login/newclient",
new StringContent(JsonConvert.SerializeObject(newClientRequest),
Encoding.UTF8, "application/json"));
newClientResponse.EnsureSuccessStatusCode();
var clientContent = await newClientResponse.Content.ReadAsStringAsync();
var clientResult = JsonConvert.DeserializeObject<NewClientResponse>(clientContent);
// Segunda requisição - token
var tokenRequest = new
{
clientId = userId,
clientName = name,
clientSecret = clientResult.Secret
};
var tokenResponse = await client.PostAsync(
$"{baseUrl}/login/token",
new StringContent(JsonConvert.SerializeObject(tokenRequest),
Encoding.UTF8, "application/json"));
tokenResponse.EnsureSuccessStatusCode();
var tokenContent = await tokenResponse.Content.ReadAsStringAsync();
var tokenResult = JsonConvert.DeserializeObject<TokenResponse>(tokenContent);
return tokenResult.Token;
}
}
}

View File

@ -1,4 +1,5 @@
using ChatMvc.LogConfig; using ChatMvc.LogConfig;
using ChatMvc.Managers;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount; using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
@ -37,9 +38,12 @@ options =>
}) })
.AddCookie(options => .AddCookie(options =>
{ {
options.ExpireTimeSpan = TimeSpan.FromMinutes(20); //options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
options.SlidingExpiration = true; //options.SlidingExpiration = true;
options.AccessDeniedPath = "/Forbidden/"; options.AccessDeniedPath = "/Forbidden/";
options.Cookie.Name = ".AspNet.SharedCookie";
options.ExpireTimeSpan = TimeSpan.FromDays(30); // Define o tempo de expiração
options.SlidingExpiration = true; // Renova o cookie a cada acesso
}) })
.AddGoogle(googleOptions => .AddGoogle(googleOptions =>
{ {
@ -51,8 +55,7 @@ options =>
microsoftOptions.ClientId = config.GetSection("Microsoft_ClientId").Value; microsoftOptions.ClientId = config.GetSection("Microsoft_ClientId").Value;
//microsoftOptions.ClientSecret = "2a7cb1bd-037a-49fa-9e5e-2b2655431af9"; //microsoftOptions.ClientSecret = "2a7cb1bd-037a-49fa-9e5e-2b2655431af9";
microsoftOptions.ClientSecret = config.GetSection("Microsoft_ClientSecret").Value; microsoftOptions.ClientSecret = config.GetSection("Microsoft_ClientSecret").Value;
}) });
;
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
@ -91,6 +94,8 @@ builder.Services.AddAntiforgery(options =>
options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
}); });
builder.Services.AddScoped<TokenManager>();
var app = builder.Build(); var app = builder.Build();
var locOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>(); var locOptions = app.Services.GetService<IOptions<RequestLocalizationOptions>>();

View File

@ -11,12 +11,14 @@
}, },
"https": { "https": {
"commandName": "Project", "commandName": "Project",
"windowsAuthentication": false,
"anonymousAuthentication": true,
"launchBrowser": true, "launchBrowser": true,
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, },
"dotnetRunMessages": true, "dotnetRunMessages": true,
"applicationUrl": "https://localhost:7078;http://localhost:5094" "applicationUrl": "https://192.168.0.13:7078;http://192.168.0.13:5094;https://localhost:7078;http://localhost:5094"
}, },
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",

View File

@ -53,8 +53,8 @@
const messageInput = $('#message-input'); const messageInput = $('#message-input');
const chatForm = $('#chat-form'); const chatForm = $('#chat-form');
token = await autenticar(id, company, name); //token = await autenticar(id, company, name);
token = '@ViewBag.Token';
// Configuração do Marked // Configuração do Marked
marked.setOptions({ marked.setOptions({
breaks: true, breaks: true,

View File

@ -0,0 +1,50 @@
@using ChatMvc.Controllers
@model IEnumerable<TextResponse>
<div class="container">
<div class="card shadow-lg mt-4">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="card-title">Documentos</h2>
<a href="@Url.Action("New", "Documents")" class="btn btn-primary">
<i class="fas fa-plus mr-2"></i>Novo
</a>
</div>
<table class="table">
<thead>
<tr>
<th>Título</th>
<th>Conteúdo</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.Title</td>
<td>@(item.Content?.Length > 80 ? item.Content.Substring(0, 80) + "..." : item.Content)</td>
<td>
<a href="@Url.Action("Edit", "Documents", new { id = item.Id })" class="btn btn-primary btn-sm">
<i class="fas fa-edit"></i> Editar
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
@section Styles {
<style>
body {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.card {
border: none;
border-radius: 15px;
}
</style>
}

View File

@ -0,0 +1,31 @@
@using ChatMvc.Controllers
@model TextRequest
<div class="container">
<div class="card shadow-lg mt-4">
<div class="card-body">
<h2 class="card-title mb-4 text-center">Novo Texto</h2>
@using (Html.BeginForm("Save", "Documents", FormMethod.Post))
{
@Html.AntiForgeryToken()
@if (Model!=null && Model.Id != null)
{
@Html.HiddenFor(m => m.Id);
}
<div class="form-group">
@Html.LabelFor(m => m.Title, "Título")
@Html.TextBoxFor(m => m.Title, new { @class = "form-control" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Content, "Conteúdo")
@Html.TextAreaFor(m => m.Content, new { @class = "form-control", rows = "5" })
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary">Salvar</button>
</div>
}
</div>
</div>
</div>

View File

@ -79,6 +79,9 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link text-white" asp-area="" asp-controller="Chat" asp-action="Index">Chat</a> <a class="nav-link text-white" asp-area="" asp-controller="Chat" asp-action="Index">Chat</a>
</li> </li>
<li class="nav-item">
<a class="nav-link text-white" asp-area="" asp-controller="Documents" asp-action="Index">Documentos</a>
</li>
} }
</ul> </ul>
@if (User!=null && User.Identity!=null && !User.Identity.IsAuthenticated) @if (User!=null && User.Identity!=null && !User.Identity.IsAuthenticated)