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
}
}