Added ping route. Allow register from authentication window.
parent
43f0e3823d
commit
cad74115e1
|
@ -11,6 +11,7 @@ using System.Net;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Media.Converters;
|
||||||
|
|
||||||
namespace LANCommander.PlaynitePlugin
|
namespace LANCommander.PlaynitePlugin
|
||||||
{
|
{
|
||||||
|
@ -85,6 +86,36 @@ namespace LANCommander.PlaynitePlugin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<AuthResponse> RegisterAsync(string username, string password)
|
||||||
|
{
|
||||||
|
var response = await Client.ExecuteAsync<AuthResponse>(new RestRequest("/api/auth/register", Method.POST).AddJsonBody(new AuthRequest()
|
||||||
|
{
|
||||||
|
UserName = username,
|
||||||
|
Password = password
|
||||||
|
}));
|
||||||
|
|
||||||
|
switch (response.StatusCode)
|
||||||
|
{
|
||||||
|
case HttpStatusCode.OK:
|
||||||
|
return response.Data;
|
||||||
|
|
||||||
|
case HttpStatusCode.BadRequest:
|
||||||
|
case HttpStatusCode.Forbidden:
|
||||||
|
case HttpStatusCode.Unauthorized:
|
||||||
|
throw new WebException(response.Data.Message);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new WebException("Could not communicate with the server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> PingAsync()
|
||||||
|
{
|
||||||
|
var response = await Client.ExecuteAsync(new RestRequest("/api/Ping", Method.GET));
|
||||||
|
|
||||||
|
return response.StatusCode == HttpStatusCode.OK;
|
||||||
|
}
|
||||||
|
|
||||||
public AuthResponse RefreshToken(AuthToken token)
|
public AuthResponse RefreshToken(AuthToken token)
|
||||||
{
|
{
|
||||||
var request = new RestRequest("/api/Auth/Refresh")
|
var request = new RestRequest("/api/Auth/Refresh")
|
||||||
|
|
|
@ -312,7 +312,8 @@ namespace LANCommander.PlaynitePlugin
|
||||||
};
|
};
|
||||||
|
|
||||||
window.Owner = PlayniteApi.Dialogs.GetCurrentAppWindow();
|
window.Owner = PlayniteApi.Dialogs.GetCurrentAppWindow();
|
||||||
window.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
|
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
window.ResizeMode = ResizeMode.NoResize;
|
||||||
window.ShowDialog();
|
window.ShowDialog();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,7 @@
|
||||||
<RowDefinition Height="auto" />
|
<RowDefinition Height="auto" />
|
||||||
<RowDefinition Height="auto" />
|
<RowDefinition Height="auto" />
|
||||||
<RowDefinition Height="auto" />
|
<RowDefinition Height="auto" />
|
||||||
|
<RowDefinition Height="auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="auto" />
|
<ColumnDefinition Width="auto" />
|
||||||
|
@ -214,6 +215,20 @@
|
||||||
<TextBox Grid.Row="1" Grid.Column="1" Name="Username" Text="{Binding UserName}" KeyDown="TextBox_KeyDown" />
|
<TextBox Grid.Row="1" Grid.Column="1" Name="Username" Text="{Binding UserName}" KeyDown="TextBox_KeyDown" />
|
||||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="Password" />
|
<TextBlock Grid.Row="2" Grid.Column="0" Text="Password" />
|
||||||
<PasswordBox Grid.Row="2" Grid.Column="1" Name="Password" PasswordChanged="Password_PasswordChanged" KeyDown="TextBox_KeyDown" />
|
<PasswordBox Grid.Row="2" Grid.Column="1" Name="Password" PasswordChanged="Password_PasswordChanged" KeyDown="TextBox_KeyDown" />
|
||||||
<Button Grid.Row="3" Grid.ColumnSpan="2" Command="{Binding LoginCommand}" x:Name="LoginButton">Login</Button>
|
|
||||||
|
<GridSplitter Grid.Row="4" />
|
||||||
|
|
||||||
|
<Grid Grid.Row="5" Grid.ColumnSpan="2">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button Grid.Row="0" Grid.Column="0" Click="LoginButton_Click" x:Name="LoginButton">Login</Button>
|
||||||
|
<Button Grid.Row="0" Grid.Column="1" Click="RegisterButton_Click" x:Name="RegisterButton">Register</Button>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
|
@ -60,6 +60,11 @@ namespace LANCommander.PlaynitePlugin.Views
|
||||||
Authenticate();
|
Authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Register();
|
||||||
|
}
|
||||||
|
|
||||||
private void Password_PasswordChanged(object sender, RoutedEventArgs e)
|
private void Password_PasswordChanged(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext != null)
|
if (DataContext != null)
|
||||||
|
@ -121,5 +126,46 @@ namespace LANCommander.PlaynitePlugin.Views
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task Register()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LoginButton.IsEnabled = false;
|
||||||
|
RegisterButton.IsEnabled = false;
|
||||||
|
RegisterButton.Content = "Working...";
|
||||||
|
|
||||||
|
if (Plugin.LANCommander == null || Plugin.LANCommander.Client == null)
|
||||||
|
Plugin.LANCommander = new LANCommanderClient(Context.ServerAddress);
|
||||||
|
else
|
||||||
|
Plugin.LANCommander.Client.BaseUrl = new Uri(Context.ServerAddress);
|
||||||
|
|
||||||
|
var response = await Plugin.LANCommander.RegisterAsync(Context.UserName, Context.Password);
|
||||||
|
|
||||||
|
Plugin.Settings.ServerAddress = Context.ServerAddress;
|
||||||
|
Plugin.Settings.AccessToken = response.AccessToken;
|
||||||
|
Plugin.Settings.RefreshToken = response.RefreshToken;
|
||||||
|
|
||||||
|
Plugin.LANCommander.Token = new AuthToken()
|
||||||
|
{
|
||||||
|
AccessToken = response.AccessToken,
|
||||||
|
RefreshToken = response.RefreshToken,
|
||||||
|
};
|
||||||
|
|
||||||
|
Context.Password = String.Empty;
|
||||||
|
|
||||||
|
Plugin.SavePluginSettings(Plugin.Settings);
|
||||||
|
|
||||||
|
Window.GetWindow(this).Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Plugin.PlayniteApi.Dialogs.ShowErrorMessage(ex.Message);
|
||||||
|
|
||||||
|
LoginButton.IsEnabled = true;
|
||||||
|
RegisterButton.IsEnabled = true;
|
||||||
|
RegisterButton.Content = "Register";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,5 +9,6 @@ namespace LANCommander.SDK.Models
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
public string RefreshToken { get; set; }
|
public string RefreshToken { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
public DateTime Expiration { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace LANCommander.Controllers.Api
|
||||||
{
|
{
|
||||||
public string AccessToken { get; set; }
|
public string AccessToken { get; set; }
|
||||||
public string RefreshToken { get; set; }
|
public string RefreshToken { get; set; }
|
||||||
|
public DateTime Expiration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LoginModel
|
public class LoginModel
|
||||||
|
@ -24,17 +25,25 @@ namespace LANCommander.Controllers.Api
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class RegisterModel
|
||||||
|
{
|
||||||
|
public string UserName { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class AuthController : ControllerBase
|
public class AuthController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly UserManager<User> UserManager;
|
private readonly UserManager<User> UserManager;
|
||||||
|
private readonly IUserStore<User> UserStore;
|
||||||
private readonly RoleManager<Role> RoleManager;
|
private readonly RoleManager<Role> RoleManager;
|
||||||
private readonly LANCommanderSettings Settings;
|
private readonly LANCommanderSettings Settings;
|
||||||
|
|
||||||
public AuthController(UserManager<User> userManager, RoleManager<Role> roleManager)
|
public AuthController(UserManager<User> userManager, IUserStore<User> userStore, RoleManager<Role> roleManager)
|
||||||
{
|
{
|
||||||
UserManager = userManager;
|
UserManager = userManager;
|
||||||
|
UserStore = userStore;
|
||||||
RoleManager = roleManager;
|
RoleManager = roleManager;
|
||||||
Settings = SettingService.GetSettings();
|
Settings = SettingService.GetSettings();
|
||||||
}
|
}
|
||||||
|
@ -44,38 +53,16 @@ namespace LANCommander.Controllers.Api
|
||||||
{
|
{
|
||||||
var user = await UserManager.FindByNameAsync(model.UserName);
|
var user = await UserManager.FindByNameAsync(model.UserName);
|
||||||
|
|
||||||
if (user != null && await UserManager.CheckPasswordAsync(user, model.Password))
|
try
|
||||||
{
|
{
|
||||||
var userRoles = await UserManager.GetRolesAsync(user);
|
var token = await Login(user, model.Password);
|
||||||
|
|
||||||
var authClaims = new List<Claim>
|
return Ok(token);
|
||||||
{
|
}
|
||||||
new Claim(ClaimTypes.Name, user.UserName),
|
catch
|
||||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
|
{
|
||||||
};
|
return Unauthorized();
|
||||||
|
|
||||||
foreach (var userRole in userRoles)
|
|
||||||
{
|
|
||||||
authClaims.Add(new Claim(ClaimTypes.Role, userRole));
|
|
||||||
}
|
|
||||||
|
|
||||||
var token = GetToken(authClaims);
|
|
||||||
var refreshToken = GenerateRefreshToken();
|
|
||||||
|
|
||||||
user.RefreshToken = refreshToken;
|
|
||||||
user.RefreshTokenExpiration = DateTime.Now.AddDays(Settings.TokenLifetime);
|
|
||||||
|
|
||||||
await UserManager.UpdateAsync(user);
|
|
||||||
|
|
||||||
return Ok(new
|
|
||||||
{
|
|
||||||
AccessToken = new JwtSecurityTokenHandler().WriteToken(token),
|
|
||||||
RefreshToken = refreshToken,
|
|
||||||
Expiration = token.ValidTo
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Unauthorized();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("Validate")]
|
[HttpPost("Validate")]
|
||||||
|
@ -125,6 +112,82 @@ namespace LANCommander.Controllers.Api
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost("Register")]
|
||||||
|
public async Task<IActionResult> Register([FromBody] RegisterModel model)
|
||||||
|
{
|
||||||
|
var user = await UserManager.FindByNameAsync(model.UserName);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
return Unauthorized(new
|
||||||
|
{
|
||||||
|
Message = "Username is unavailable"
|
||||||
|
});
|
||||||
|
|
||||||
|
user = new User();
|
||||||
|
|
||||||
|
await UserStore.SetUserNameAsync(user, model.UserName, CancellationToken.None);
|
||||||
|
|
||||||
|
var result = await UserManager.CreateAsync(user, model.Password);
|
||||||
|
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var token = await Login(user, model.Password);
|
||||||
|
|
||||||
|
return Ok(token);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return BadRequest(new
|
||||||
|
{
|
||||||
|
Message = "An unknown error occurred"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unauthorized(new
|
||||||
|
{
|
||||||
|
Message = "Error:\n" + String.Join('\n', result.Errors.Select(e => e.Description))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<TokenModel> Login(User user, string password)
|
||||||
|
{
|
||||||
|
if (user != null && await UserManager.CheckPasswordAsync(user, password))
|
||||||
|
{
|
||||||
|
var userRoles = await UserManager.GetRolesAsync(user);
|
||||||
|
|
||||||
|
var authClaims = new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Name, user.UserName),
|
||||||
|
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var userRole in userRoles)
|
||||||
|
{
|
||||||
|
authClaims.Add(new Claim(ClaimTypes.Role, userRole));
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = GetToken(authClaims);
|
||||||
|
var refreshToken = GenerateRefreshToken();
|
||||||
|
|
||||||
|
user.RefreshToken = refreshToken;
|
||||||
|
user.RefreshTokenExpiration = DateTime.Now.AddDays(Settings.TokenLifetime);
|
||||||
|
|
||||||
|
await UserManager.UpdateAsync(user);
|
||||||
|
|
||||||
|
return new TokenModel()
|
||||||
|
{
|
||||||
|
AccessToken = new JwtSecurityTokenHandler().WriteToken(token),
|
||||||
|
RefreshToken = refreshToken,
|
||||||
|
Expiration = token.ValidTo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Invalid username or password");
|
||||||
|
}
|
||||||
|
|
||||||
private JwtSecurityToken GetToken(List<Claim> authClaims)
|
private JwtSecurityToken GetToken(List<Claim> authClaims)
|
||||||
{
|
{
|
||||||
var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Settings.TokenSecret));
|
var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Settings.TokenSecret));
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LANCommander.Controllers.Api
|
||||||
|
{
|
||||||
|
public class PingController : Controller
|
||||||
|
{
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
return Ok("Pong!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue