mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Handling autologin and logout
This commit is contained in:
parent
d7972704dd
commit
440e5f4f14
@ -87,6 +87,12 @@ namespace Kyoo.Authentication
|
||||
|
||||
services.AddControllers();
|
||||
|
||||
// TODO handle direct-videos with bearers (probably add a ?token query param and a app.Use to translate that for videos)
|
||||
|
||||
// TODO Support sign-out, check if login work, check if tokens should be stored.
|
||||
|
||||
// TODO remove unused/commented code, add documentation.
|
||||
|
||||
// services.AddIdentityCore<User>()
|
||||
// .AddSignInManager()
|
||||
// .AddDefaultTokenProviders()
|
||||
@ -157,8 +163,7 @@ namespace Kyoo.Authentication
|
||||
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
AuthorizationPolicyBuilder scheme = new(IdentityConstants.ApplicationScheme,
|
||||
JwtBearerDefaults.AuthenticationScheme);
|
||||
AuthorizationPolicyBuilder scheme = new(JwtBearerDefaults.AuthenticationScheme);
|
||||
options.DefaultPolicy = scheme.RequireAuthenticatedUser().Build();
|
||||
|
||||
string[] permissions = {"Read", "Write", "Play", "Admin"};
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using IdentityModel;
|
||||
using IdentityServer4;
|
||||
using Kyoo.Models;
|
||||
|
||||
namespace Kyoo.Authentication
|
||||
@ -26,14 +27,16 @@ namespace Kyoo.Authentication
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a user to a ClaimsPrincipal.
|
||||
/// Convert a user to an <see cref="IdentityServerUser"/>.
|
||||
/// </summary>
|
||||
/// <param name="user">The user to convert</param>
|
||||
/// <returns>A ClaimsPrincipal representing the user</returns>
|
||||
public static ClaimsPrincipal ToPrincipal(this User user)
|
||||
/// <returns>The corresponding identity server user.</returns>
|
||||
public static IdentityServerUser ToIdentityUser(this User user)
|
||||
{
|
||||
ClaimsIdentity id = new (user.GetClaims());
|
||||
return new ClaimsPrincipal(id);
|
||||
return new(user.ID.ToString())
|
||||
{
|
||||
DisplayName = user.Username
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
// using System.Threading.Tasks;
|
||||
// using IdentityServer4.EntityFramework.Entities;
|
||||
// using IdentityServer4.EntityFramework.Extensions;
|
||||
// using IdentityServer4.EntityFramework.Interfaces;
|
||||
// using IdentityServer4.EntityFramework.Options;
|
||||
// using Kyoo.Models;
|
||||
// using Microsoft.AspNetCore.Identity;
|
||||
// using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
// using Microsoft.EntityFrameworkCore;
|
||||
// using Microsoft.Extensions.Options;
|
||||
//
|
||||
// namespace Kyoo
|
||||
// {
|
||||
// // The configuration's database is named ConfigurationDbContext.
|
||||
// public class IdentityDatabase : IdentityDbContext<User>, IPersistedGrantDbContext
|
||||
// {
|
||||
// private readonly IOptions<OperationalStoreOptions> _operationalStoreOptions;
|
||||
//
|
||||
// public IdentityDatabase(DbContextOptions<IdentityDatabase> options, IOptions<OperationalStoreOptions> operationalStoreOptions)
|
||||
// : base(options)
|
||||
// {
|
||||
// _operationalStoreOptions = operationalStoreOptions;
|
||||
// }
|
||||
//
|
||||
// public DbSet<User> Accounts { get; set; }
|
||||
//
|
||||
// protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
// {
|
||||
// base.OnModelCreating(modelBuilder);
|
||||
// modelBuilder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value);
|
||||
//
|
||||
// modelBuilder.Entity<User>().ToTable("User");
|
||||
// modelBuilder.Entity<IdentityUserRole<string>>().ToTable("UserRole");
|
||||
// modelBuilder.Entity<IdentityUserLogin<string>>().ToTable("UserLogin");
|
||||
// modelBuilder.Entity<IdentityUserClaim<string>>().ToTable("UserClaim");
|
||||
// modelBuilder.Entity<IdentityRole>().ToTable("UserRoles");
|
||||
// modelBuilder.Entity<IdentityRoleClaim<string>>().ToTable("UserRoleClaim");
|
||||
// modelBuilder.Entity<IdentityUserToken<string>>().ToTable("UserToken");
|
||||
// }
|
||||
//
|
||||
// public Task<int> SaveChangesAsync() => base.SaveChangesAsync();
|
||||
//
|
||||
// public DbSet<PersistedGrant> PersistedGrants { get; set; }
|
||||
// public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }
|
||||
//
|
||||
// }
|
||||
// }
|
@ -1,22 +0,0 @@
|
||||
// using System;
|
||||
// using IdentityModel;
|
||||
// using Microsoft.AspNetCore.Identity;
|
||||
//
|
||||
// namespace Kyoo.Models
|
||||
// {
|
||||
// public class User : IdentityUser
|
||||
// {
|
||||
// public string OTAC { get; set; }
|
||||
// public DateTime? OTACExpires { get; set; }
|
||||
//
|
||||
// public string GenerateOTAC(TimeSpan validFor)
|
||||
// {
|
||||
// string otac = CryptoRandom.CreateUniqueId();
|
||||
// string hashed = otac; // TODO should add a good hashing here.
|
||||
//
|
||||
// OTAC = hashed;
|
||||
// OTACExpires = DateTime.UtcNow.Add(validFor);
|
||||
// return otac;
|
||||
// }
|
||||
// }
|
||||
// }
|
@ -5,7 +5,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4;
|
||||
using IdentityServer4.Extensions;
|
||||
using IdentityServer4.Models;
|
||||
using IdentityServer4.Services;
|
||||
@ -35,15 +34,9 @@ namespace Kyoo.Authentication.Views
|
||||
/// </summary>
|
||||
private readonly IUserRepository _users;
|
||||
/// <summary>
|
||||
/// The identity server interaction service to login users.
|
||||
/// </summary>
|
||||
// private readonly IIdentityServerInteractionService _interaction;
|
||||
/// <summary>
|
||||
/// A file manager to send profile pictures
|
||||
/// </summary>
|
||||
private readonly IFileManager _files;
|
||||
// private readonly SignInManager<User> _signInManager;
|
||||
|
||||
/// <summary>
|
||||
/// Options about authentication. Those options are monitored and reloads are supported.
|
||||
/// </summary>
|
||||
@ -54,20 +47,15 @@ namespace Kyoo.Authentication.Views
|
||||
/// Create a new <see cref="AccountApi"/> handle to handle login/users requests.
|
||||
/// </summary>
|
||||
/// <param name="users">The user repository to create and manage users</param>
|
||||
/// <param name="interaction">The identity server interaction service to login users.</param>
|
||||
/// <param name="files">A file manager to send profile pictures</param>
|
||||
/// <param name="options">Authentication options (this may be hot reloaded)</param>
|
||||
public AccountApi(IUserRepository users,
|
||||
// IIdentityServerInteractionService interaction,
|
||||
IFileManager files,
|
||||
IOptions<AuthenticationOption> options)
|
||||
//, SignInManager<User> signInManager)
|
||||
{
|
||||
_users = users;
|
||||
// _interaction = interaction;
|
||||
_files = files;
|
||||
_options = options;
|
||||
// _signInManager = signInManager;
|
||||
}
|
||||
|
||||
|
||||
@ -119,7 +107,6 @@ namespace Kyoo.Authentication.Views
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login([FromBody] LoginRequest login)
|
||||
{
|
||||
// AuthorizationRequest context = await _interaction.GetAuthorizationContextAsync(login.ReturnURL);
|
||||
User user = await _users.GetOrDefault(x => x.Username == login.Username);
|
||||
|
||||
if (user == null)
|
||||
@ -127,7 +114,7 @@ namespace Kyoo.Authentication.Views
|
||||
if (!PasswordUtils.CheckPassword(login.Password, user.Password))
|
||||
return Unauthorized();
|
||||
|
||||
// await _signInManager.SignInAsync(user, login.StayLoggedIn);
|
||||
await HttpContext.SignInAsync(user.ToIdentityUser(), StayLogged(login.StayLoggedIn));
|
||||
return Ok(new { RedirectUrl = login.ReturnURL, IsOk = true });
|
||||
}
|
||||
|
||||
@ -143,20 +130,16 @@ namespace Kyoo.Authentication.Views
|
||||
User user = (await _users.GetAll()).FirstOrDefault(x => x.ExtraData.GetValueOrDefault("otac") == otac.Otac);
|
||||
if (user == null)
|
||||
return Unauthorized();
|
||||
if (DateTime.ParseExact(user.ExtraData["otac-expire"], "s", CultureInfo.InvariantCulture) <= DateTime.UtcNow)
|
||||
if (DateTime.ParseExact(user.ExtraData["otac-expire"], "s", CultureInfo.InvariantCulture) <=
|
||||
DateTime.UtcNow)
|
||||
{
|
||||
return BadRequest(new
|
||||
{
|
||||
code = "ExpiredOTAC", description = "The OTAC has expired. Try to login with your password."
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
IdentityServerUser iduser = new(user.ID.ToString())
|
||||
{
|
||||
DisplayName = user.Username
|
||||
};
|
||||
|
||||
await HttpContext.SignInAsync(iduser, StayLogged(otac.StayLoggedIn));
|
||||
// await _signInManager.SignInAsync(user, otac.StayLoggedIn);
|
||||
await HttpContext.SignInAsync(user.ToIdentityUser(), StayLogged(otac.StayLoggedIn));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -167,11 +150,11 @@ namespace Kyoo.Authentication.Views
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
// await _signInManager.SignOutAsync();
|
||||
await HttpContext.SignOutAsync();
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// TODO check with the extension method
|
||||
/// <inheritdoc />
|
||||
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
|
||||
{
|
||||
User user = await _users.GetOrDefault(int.Parse(context.Subject.GetSubjectId()));
|
||||
@ -181,12 +164,18 @@ namespace Kyoo.Authentication.Views
|
||||
context.IssuedClaims.Add(new Claim("permissions", string.Join(',', user.Permissions)));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task IsActiveAsync(IsActiveContext context)
|
||||
{
|
||||
User user = await _users.GetOrDefault(int.Parse(context.Subject.GetSubjectId()));
|
||||
context.IsActive = user != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the user's profile picture.
|
||||
/// </summary>
|
||||
/// <param name="slug">The user slug</param>
|
||||
/// <returns>The profile picture of the user or 404 if not found</returns>
|
||||
[HttpGet("picture/{slug}")]
|
||||
public async Task<IActionResult> GetPicture(string slug)
|
||||
{
|
||||
@ -197,6 +186,11 @@ namespace Kyoo.Authentication.Views
|
||||
return _files.FileResult(path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update profile information (email, username, profile picture...)
|
||||
/// </summary>
|
||||
/// <param name="data">The new information</param>
|
||||
/// <returns>The edited user</returns>
|
||||
[HttpPut]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<User>> Update([FromForm] AccountUpdateRequest data)
|
||||
@ -218,6 +212,10 @@ namespace Kyoo.Authentication.Views
|
||||
return await _users.Edit(user, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get permissions for a non connected user.
|
||||
/// </summary>
|
||||
/// <returns>The list of permissions of a default user.</returns>
|
||||
[HttpGet("permissions")]
|
||||
public ActionResult<IEnumerable<string>> GetDefaultPermissions()
|
||||
{
|
||||
|
@ -19,7 +19,8 @@ namespace Kyoo.Controllers
|
||||
/// or proxy them from a distant server
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If no file exists at the given path, you should return a NotFoundResult or handle it gracefully.
|
||||
/// If no file exists at the given path or if the path is null, a NotFoundResult is returned
|
||||
/// to handle it gracefully.
|
||||
/// </remarks>
|
||||
/// <param name="path">The path of the file.</param>
|
||||
/// <param name="rangeSupport">
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit d3a860fa8ffccade9e3b17022482e11c9a18303e
|
||||
Subproject commit a0f8fe4de48a0f0770646d6052a09c551b6442dd
|
Loading…
x
Reference in New Issue
Block a user