mirror of
https://github.com/ryzij/URL-Shortener.git
synced 2026-07-14 03:56:58 +00:00
Compare commits
6 Commits
99973eba04
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a9746b8d0d | |||
| 067a1a6055 | |||
| da47d7fdf3 | |||
| d659a0289f | |||
| 4a4ee24ce7 | |||
| e55c54e75d |
@@ -3,6 +3,9 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using URL_Shortener.DTO;
|
using URL_Shortener.DTO;
|
||||||
using URL_Shortener.Models;
|
using URL_Shortener.Models;
|
||||||
using HashidsNet;
|
using HashidsNet;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using URL_Shortener.Extensions;
|
||||||
|
|
||||||
namespace URL_Shortener.Controllers
|
namespace URL_Shortener.Controllers
|
||||||
{
|
{
|
||||||
@@ -38,13 +41,15 @@ namespace URL_Shortener.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
public async Task<IActionResult> CreateShortUrlAsync(CreateShortUrlDto dto)
|
public async Task<IActionResult> CreateShortUrlAsync(CreateShortUrlDto dto)
|
||||||
{
|
{
|
||||||
var shortUrl = new ShortUrl
|
var shortUrl = new ShortUrl
|
||||||
{
|
{
|
||||||
OriginalUrl = dto.OriginalUrl,
|
OriginalUrl = dto.OriginalUrl,
|
||||||
ExpirationDateTime = dto.ExpirationDateTime,
|
ExpirationDateTime = dto.ExpirationDateTime,
|
||||||
ClickLimit = dto.ClickLimit
|
ClickLimit = dto.ClickLimit,
|
||||||
|
UserId = int.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!)
|
||||||
};
|
};
|
||||||
await _db.ShortUrls.AddAsync(shortUrl);
|
await _db.ShortUrls.AddAsync(shortUrl);
|
||||||
await _db.SaveChangesAsync();
|
await _db.SaveChangesAsync();
|
||||||
@@ -55,12 +60,16 @@ namespace URL_Shortener.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPatch("{id:int}")]
|
[HttpPatch("{id:int}")]
|
||||||
|
[Authorize]
|
||||||
public async Task<IActionResult> UpdateShortUrlAsync(int id, UpdateShortUrlDto dto)
|
public async Task<IActionResult> UpdateShortUrlAsync(int id, UpdateShortUrlDto dto)
|
||||||
{
|
{
|
||||||
var shortUrl = await _db.ShortUrls.FindAsync(id);
|
var shortUrl = await _db.ShortUrls.FindAsync(id);
|
||||||
if (shortUrl == null)
|
if (shortUrl == null)
|
||||||
return NotFound("Short URL not found");
|
return NotFound("Short URL not found");
|
||||||
|
|
||||||
|
if (!User.CompareId(shortUrl.UserId))
|
||||||
|
throw new Exception("Not authorized");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(dto.OriginalUrl))
|
if (!string.IsNullOrEmpty(dto.OriginalUrl))
|
||||||
shortUrl.OriginalUrl = dto.OriginalUrl;
|
shortUrl.OriginalUrl = dto.OriginalUrl;
|
||||||
if (dto.ExpirationDateTime.HasValue)
|
if (dto.ExpirationDateTime.HasValue)
|
||||||
@@ -78,12 +87,16 @@ namespace URL_Shortener.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpDelete("{id:int}")]
|
[HttpDelete("{id:int}")]
|
||||||
|
[Authorize]
|
||||||
public async Task<IActionResult> DeleteShortUrlByIdAsync(int id)
|
public async Task<IActionResult> DeleteShortUrlByIdAsync(int id)
|
||||||
{
|
{
|
||||||
var shortUrl = await _db.ShortUrls.FindAsync(id);
|
var shortUrl = await _db.ShortUrls.FindAsync(id);
|
||||||
if (shortUrl == null)
|
if (shortUrl == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|
||||||
|
if (!User.CompareId(shortUrl.UserId))
|
||||||
|
throw new Exception("Not authorized");
|
||||||
|
|
||||||
_db.ShortUrls.Remove(shortUrl);
|
_db.ShortUrls.Remove(shortUrl);
|
||||||
|
|
||||||
var clickInfos = _db.ClickInfos.Where(c => c.ShortUrlId == id);
|
var clickInfos = _db.ClickInfos.Where(c => c.ShortUrlId == id);
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ namespace URL_Shortener.Controllers
|
|||||||
[HttpPost("register")]
|
[HttpPost("register")]
|
||||||
public async Task<IActionResult> RegisterAsync(RegisterUserDTO dto)
|
public async Task<IActionResult> RegisterAsync(RegisterUserDTO dto)
|
||||||
{
|
{
|
||||||
await _userService.RegisterAsync(dto.Name, dto.Email, dto.Password);
|
var jwt = await _userService.RegisterAsync(dto.Name, dto.Email, dto.Password);
|
||||||
return Ok();
|
return Ok(jwt);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("login")]
|
[HttpPost("login")]
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace URL_Shortener.Extensions;
|
||||||
|
|
||||||
|
public static class ClaimsPrincipalExtensions
|
||||||
|
{
|
||||||
|
public static bool CompareId(this ClaimsPrincipal claimsPrincipal, int userId)
|
||||||
|
{
|
||||||
|
return int.TryParse(claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier), out int id) &&
|
||||||
|
id == userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using URL_Shortener;
|
using URL_Shortener;
|
||||||
using URL_Shortener.Services;
|
using URL_Shortener.Services;
|
||||||
using URL_Shortener.Settings;
|
using URL_Shortener.Settings;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Microsoft.OpenApi;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
@@ -12,13 +16,40 @@ builder.Services.AddControllers();
|
|||||||
builder.Services.AddOpenApi();
|
builder.Services.AddOpenApi();
|
||||||
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen(options =>
|
||||||
|
{
|
||||||
|
options.AddSecurityDefinition("bearer", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Type = SecuritySchemeType.Http,
|
||||||
|
Scheme = "bearer",
|
||||||
|
BearerFormat = "JWT",
|
||||||
|
Description = "JWT Authorization header using the Bearer scheme."
|
||||||
|
});
|
||||||
|
|
||||||
|
options.AddSecurityRequirement(document => new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
[new OpenApiSecuritySchemeReference("bearer", document)] = []
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddSingleton<HashidsNet.Hashids>();
|
builder.Services.AddSingleton<HashidsNet.Hashids>();
|
||||||
|
|
||||||
builder.Services.AddScoped<UserService>();
|
builder.Services.AddScoped<UserService>();
|
||||||
builder.Services.AddScoped<JwtService>();
|
builder.Services.AddScoped<JwtService>();
|
||||||
builder.Services.Configure<AuthSettings>(builder.Configuration.GetSection("AuthSettings"));
|
|
||||||
|
var authSettings = builder.Configuration.GetSection("AuthSettings");
|
||||||
|
builder.Services.Configure<AuthSettings>(authSettings);
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
|
.AddJwtBearer(o => o.TokenValidationParameters = new()
|
||||||
|
{
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidateAudience = false,
|
||||||
|
ValidateIssuer = false,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
|
||||||
|
authSettings.Get<AuthSettings>()!.SecretKey))
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddDbContext<AppDbContext>(options =>
|
builder.Services.AddDbContext<AppDbContext>(options =>
|
||||||
{
|
{
|
||||||
@@ -45,8 +76,7 @@ using (var scope = app.Services.CreateScope())
|
|||||||
retry.Execute(db.Database.Migrate);
|
retry.Execute(db.Database.Migrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
//app.UseHttpsRedirection();
|
app.UseAuthentication();
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ namespace URL_Shortener.Services
|
|||||||
public string GenerateToken(User user)
|
public string GenerateToken(User user)
|
||||||
{
|
{
|
||||||
var claims = new List<Claim>() {
|
var claims = new List<Claim>() {
|
||||||
new("userName", user.Name),
|
new(ClaimTypes.Name, user.Name),
|
||||||
new("userEmail", user.Email),
|
new(ClaimTypes.Email, user.Email),
|
||||||
new("id", user.Id.ToString())
|
new(ClaimTypes.NameIdentifier, user.Id.ToString())
|
||||||
};
|
};
|
||||||
var jwt = new JwtSecurityToken(
|
var jwt = new JwtSecurityToken(
|
||||||
expires: DateTime.UtcNow.Add(options.Value.Expires),
|
expires: DateTime.UtcNow.Add(options.Value.Expires),
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace URL_Shortener.Services
|
|||||||
private readonly AppDbContext _db = db;
|
private readonly AppDbContext _db = db;
|
||||||
private readonly JwtService _jwtService = jwtService;
|
private readonly JwtService _jwtService = jwtService;
|
||||||
|
|
||||||
public async Task RegisterAsync(string userName, string email, string password, CancellationToken cancellationToken = default)
|
public async Task<string> RegisterAsync(string userName, string email, string password, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
if (await _db.Users.FirstOrDefaultAsync(u => u.Email == email, cancellationToken) != null)
|
if (await _db.Users.FirstOrDefaultAsync(u => u.Email == email, cancellationToken) != null)
|
||||||
throw new Exception("This user already exists.");
|
throw new Exception("This user already exists.");
|
||||||
@@ -23,6 +23,8 @@ namespace URL_Shortener.Services
|
|||||||
|
|
||||||
await _db.Users.AddAsync(user, cancellationToken);
|
await _db.Users.AddAsync(user, cancellationToken);
|
||||||
await _db.SaveChangesAsync(cancellationToken);
|
await _db.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
return _jwtService.GenerateToken(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> LoginAsync(string email, string password, CancellationToken cancellationToken = default)
|
public async Task<string> LoginAsync(string email, string password, CancellationToken cancellationToken = default)
|
||||||
|
|||||||
Reference in New Issue
Block a user