using Blahblah.FlowerStory.Server.Data; using Blahblah.FlowerStory.Server.Data.Model; using Microsoft.AspNetCore.Mvc; namespace Blahblah.FlowerStory.Server.Controller { /// /// 用户会话相关服务 /// [ApiController] [Produces("application/json")] [Route("users")] public partial class UserController : BaseController { /// /// 构造用户会话服务 /// /// 数据库对象 /// 日志对象 public UserController(FlowerDatabase db, ILogger logger) : base(db, logger) { } /// /// 用户登录 /// /// /// 提交示例: /// /// POST /users/auth /// { /// "id": "blahblah", /// "password": "pwd123" /// } /// /// /// 登录参数 /// 成功登录则返回自定义认证头 /// 返回自定义认证头 /// 认证失败 /// 未找到用户 [Route("auth")] [Consumes("application/json")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status404NotFound)] [HttpPost] public ActionResult Authenticate([FromBody] LoginParamter login) { #if DEBUG logger?.LogInformation("user \"{user}\" try to login with password \"{password}\"", login.Id, login.Password); #endif var user = database.Users.FirstOrDefault(u => u.UserId == login.Id); if (user == null) { logger?.LogWarning("user \"{user}\" not found", login.Id); return NotFound(); } // comput password hash with salt string hash = HashPassword(login.Password, login.Id); if (hash != user.Password) { logger?.LogWarning("hash result {hash}, unauthorized with hash {password}", hash, user.Password); return Unauthorized(); } // record the session // TODO: singleton token var now = DateTimeOffset.UtcNow; var expires = 1200; // 20 minutes var token = new TokenItem { Id = Guid.NewGuid().ToString("N"), UserId = user.Id, LogonDateUnixTime = now.ToUnixTimeMilliseconds(), ActiveDateUnixTime = now.ToUnixTimeMilliseconds(), ExpireDateUnixTime = now.AddSeconds(expires).ToUnixTimeMilliseconds(), ExpireSeconds = expires, ClientApp = "browser", // TODO: support app later ClientAgent = Request.Headers.UserAgent }; database.Tokens.Add(token); user.ActiveDateUnixTime = token.ActiveDateUnixTime; database.Users.Update(user); SaveDatabase(); Response.Headers.Add(AuthHeader, token.Id); return Ok(); } /// /// 注册用户 /// /// /// 提交示例: /// /// POST /users/register /// { /// "id": "blahblah", /// "password": "pwd123", /// "userName": "Blah blah", /// "email": "blah@example.com", /// "mobile": "18012345678" /// } /// /// /// 注册参数 /// 成功注册则返回已注册的用户对象 /// 返回已注册的用户对象 /// 用户重复或其他服务器错误 [Route("register")] [Consumes("application/json")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] [HttpPost] public ActionResult Register([FromBody] UserParameter user) { #if DEBUG logger?.LogInformation("user register, {user}", user); #endif var u = database.Users.FirstOrDefault(u => u.UserId == user.Id); if (u != null) { logger?.LogWarning("duplicate user \"{id}\"", user.Id); return Problem("duplicateUser", "users/register", 500); } var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var item = new UserItem { UserId = user.Id, Password = HashPassword(user.Password, user.Id), Level = UserCommon, RegisterDateUnixTime = now, ActiveDateUnixTime = now, Name = user.UserName, Email = user.Email, Mobile = user.Mobile }; database.Users.Add(item); SaveDatabase(); return Ok(item); } /// /// 修改用户 /// /// /// 提交示例: /// /// POST /users/update /// { /// "userName": "Blah blah", /// "email": "blah@example.com", /// "mobile": "18012345678" /// } /// /// /// 修改参数 /// 修改成功则返回已修改的用户对象 /// 返回已修改的用户对象 /// 认证头未找到 /// 服务器未找到登录会话 /// 用户权限不足 /// 未找到关联用户 [Route("update")] [Consumes("application/json")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] [HttpPost] public ActionResult Update([FromBody] UpdateParameter update) { #if DEBUG logger?.LogInformation("user update, {user}", update); #endif var (result, user) = CheckPermission(); if (result != null) { return result; } if (user == null) { return NotFound(); } var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); user.ActiveDateUnixTime = now; user.Name = update.UserName; user.Email = update.Email; user.Mobile = update.Mobile; database.Users.Update(user); SaveDatabase(); return Ok(user); } //#if DEBUG /// /// 获取所有用户 /// /// [Route("query")] [HttpGet] public ActionResult GetUsers() { return Ok(database.Users.ToArray()); } /// /// 获取所有 token /// /// [Route("tokens")] [HttpGet] public ActionResult GetTokens() { return Ok(database.Tokens.ToArray()); } //#endif } }