Merge pull request !4 from Argo-QQ/dev-#IS7RM

This commit is contained in:
Argo-QQ 2019-03-04 17:11:59 +08:00 committed by Argo
commit 0900c9e299
24 changed files with 389 additions and 14 deletions

View File

@ -2,9 +2,11 @@
using Bootstrap.DataAccess; using Bootstrap.DataAccess;
using Longbow; using Longbow;
using Longbow.Configuration; using Longbow.Configuration;
using Longbow.Web;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System; using System;
using System.Linq; using System.Linq;
@ -34,13 +36,14 @@ namespace Bootstrap.Admin.Controllers
/// Login the specified userName, password and remember. /// Login the specified userName, password and remember.
/// </summary> /// </summary>
/// <returns>The login.</returns> /// <returns>The login.</returns>
/// <param name="onlineUserSvr"></param>
/// <param name="userName">User name.</param> /// <param name="userName">User name.</param>
/// <param name="password">Password.</param> /// <param name="password">Password.</param>
/// <param name="remember">Remember.</param> /// <param name="remember">Remember.</param>
[HttpPost] [HttpPost]
public async Task<IActionResult> Login(string userName, string password, string remember) public async Task<IActionResult> Login([FromServices]IOnlineUsers onlineUserSvr, string userName, string password, string remember)
{ {
if (UserHelper.Authenticate(userName, password)) if (UserHelper.Authenticate(userName, password, loginUser => CreateLoginUser(onlineUserSvr, HttpContext, loginUser)))
{ {
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.Name, userName)); identity.AddClaim(new Claim(ClaimTypes.Name, userName));
@ -51,6 +54,21 @@ namespace Bootstrap.Admin.Controllers
return Redirect(originUrl); return Redirect(originUrl);
} }
/// <summary>
///
/// </summary>
/// <param name="onlineUserSvr"></param>
/// <param name="context"></param>
/// <param name="loginUser"></param>
internal static void CreateLoginUser(IOnlineUsers onlineUserSvr, HttpContext context, LoginUser loginUser)
{
var agent = new UserAgent(context.Request.Headers["User-Agent"]);
loginUser.Ip = context.Connection.RemoteIpAddress?.ToString();
loginUser.City = onlineUserSvr.RetrieveLocaleByIp(loginUser.Ip);
loginUser.Browser = $"{agent.Browser.Name} {agent.Browser.Version}";
loginUser.OS = $"{agent.OS.Name} {agent.OS.Version}";
}
/// <summary> /// <summary>
/// Logout this instance. /// Logout this instance.
/// </summary> /// </summary>

View File

@ -52,6 +52,12 @@ namespace Bootstrap.Admin.Controllers
/// <returns></returns> /// <returns></returns>
public ActionResult Logs() => View(new NavigatorBarModel(this)); public ActionResult Logs() => View(new NavigatorBarModel(this));
/// <summary>
///
/// </summary>
/// <returns></returns>
public ActionResult Logins() => View(new NavigatorBarModel(this));
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>

View File

@ -3,6 +3,8 @@ using Bootstrap.Security;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
namespace Bootstrap.Admin.Controllers.Api namespace Bootstrap.Admin.Controllers.Api
{ {
@ -16,20 +18,28 @@ namespace Bootstrap.Admin.Controllers.Api
[ApiController] [ApiController]
public class LoginController : ControllerBase public class LoginController : ControllerBase
{ {
/// <summary>
/// 获得登录历史记录
/// </summary>
/// <returns></returns>
[HttpGet]
public IEnumerable<LoginUser> Get() => LoginHelper.Retrieves();
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="onlineUserSvr"></param>
/// <param name="value"></param> /// <param name="value"></param>
/// <returns></returns> /// <returns></returns>
[AllowAnonymous] [AllowAnonymous]
[HttpPost] [HttpPost]
public string Post([FromBody]JObject value) public string Post([FromServices]IOnlineUsers onlineUserSvr, [FromBody]JObject value)
{ {
string token = null; string token = null;
dynamic user = value; dynamic user = value;
string userName = user.userName; string userName = user.userName;
string password = user.password; string password = user.password;
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password) && UserHelper.Authenticate(userName, password)) if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password) && UserHelper.Authenticate(userName, password, loginUser => AccountController.CreateLoginUser(onlineUserSvr, HttpContext, loginUser)))
{ {
token = BootstrapAdminJwtTokenHandler.CreateToken(userName); token = BootstrapAdminJwtTokenHandler.CreateToken(userName);
} }

View File

@ -0,0 +1,29 @@
@model NavigatorBarModel
@{
ViewBag.Title = "登录日志";
}
@section css {
<environment include="Development">
<link href="~/lib/bootstrap-table/bootstrap-table.css" rel="stylesheet" />
</environment>
<environment exclude="Development">
<link href="~/lib/bootstrap-table/bootstrap-table.min.css" rel="stylesheet" />
</environment>
}
@section javascript {
<environment include="Development">
<script src="~/lib/bootstrap-table/bootstrap-table.js"></script>
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.js"></script>
</environment>
<environment exclude="Development">
<script src="~/lib/bootstrap-table/bootstrap-table.min.js"></script>
<script src="~/lib/bootstrap-table/locale/bootstrap-table-zh-CN.min.js"></script>
</environment>
<script src="~/js/logins.js" asp-append-version="true"></script>
}
<div class="card">
<div class="card-header">在线用户<span class="pull-right"><a id="refreshUsers" href="javascript:;" class="fa fa-refresh" title="点击刷新" data-toggle="tooltip" data-placement="left"></a></span></div>
<div class="card-body" style="padding-top: 25px;">
<table></table>
</div>
</div>

View File

@ -1,6 +1,6 @@
@model NavigatorBarModel @model NavigatorBarModel
@{ @{
ViewBag.Title = "系统日志"; ViewBag.Title = "操作日志";
} }
@section css { @section css {
<environment include="Development"> <environment include="Development">

View File

@ -65,6 +65,7 @@
"KeepExceptionsPeriod": 12, "KeepExceptionsPeriod": 12,
"KeepLogsPeriod": 12, "KeepLogsPeriod": 12,
"CookieExpiresDays": 7, "CookieExpiresDays": 7,
"KeepLoginLogsPeriod": 7,
"LongbowCache": { "LongbowCache": {
"Enabled": true, "Enabled": true,
"CorsItems": [ "CorsItems": [

View File

@ -0,0 +1,31 @@
// 登录日志
$(function () {
var apiUrl = "api/Login";
var $table = $('table').smartTable({
url: apiUrl,
method: "get",
sidePagination: "client",
showToggle: false,
showRefresh: false,
showColumns: false,
columns: [
{
title: "序号", formatter: function (value, row, index) {
var options = $table.bootstrapTable('getOptions');
return options.pageSize * (options.pageNumber - 1) + index + 1;
}
},
{ title: "登陆名称", field: "UserName" },
{ title: "登录时间", field: "LoginTime" },
{ title: "主机", field: "Ip" },
{ title: "登录地点", field: "City" },
{ title: "浏览器", field: "Browser" },
{ title: "操作系统", field: "OS" },
{ title: "登录结果", field: "Result" }
]
});
$('#refreshUsers').tooltip().on('click', function () {
$table.bootstrapTable('refresh');
});
});

View File

@ -116,6 +116,17 @@ namespace Bootstrap.DataAccess.MongoDB
return DBAccess.GetCollection<BootstrapMenu>("Navigations"); return DBAccess.GetCollection<BootstrapMenu>("Navigations");
} }
} }
/// <summary>
///
/// </summary>
public static IMongoCollection<DataAccess.LoginUser> LoginUsers
{
get
{
return DBAccess.GetCollection<DataAccess.LoginUser>("LoginLogs");
}
}
#endregion #endregion
private static void InitDb() private static void InitDb()
@ -220,6 +231,15 @@ namespace Bootstrap.DataAccess.MongoDB
md.IdMemberMap.SetIgnoreIfDefault(true); md.IdMemberMap.SetIgnoreIfDefault(true);
}); });
} }
if (!BsonClassMap.IsClassMapRegistered(typeof(DataAccess.LoginUser)))
{
BsonClassMap.RegisterClassMap<DataAccess.LoginUser>(md =>
{
md.AutoMap();
md.IdMemberMap.SetSerializer(new StringSerializer(BsonType.ObjectId));
md.IdMemberMap.SetIgnoreIfDefault(true);
});
}
} }
} }
} }

View File

@ -0,0 +1,28 @@
using MongoDB.Driver;
using System.Collections.Generic;
namespace Bootstrap.DataAccess.MongoDB
{
/// <summary>
///
/// </summary>
public class LoginUser : DataAccess.LoginUser
{
/// <summary>
///
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public override bool Log(DataAccess.LoginUser user)
{
DbManager.LoginUsers.InsertOne(user);
return true;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override IEnumerable<DataAccess.LoginUser> Retrieves() => DbManager.LoginUsers.Find(FilterDefinition<DataAccess.LoginUser>.Empty).SortByDescending(user => user.LoginTime).ToList();
}
}

View File

@ -0,0 +1,34 @@
using Longbow.Cache;
using Longbow.Data;
using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
/// <summary>
///
/// </summary>
public static class LoginHelper
{
/// <summary>
///
/// </summary>
public const string RetrieveLoginLogsDataKey = "LoginHelper-Retrieves";
/// <summary>
///
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public static bool Log(LoginUser user)
{
var ret = DbContextManager.Create<LoginUser>().Log(user);
if (ret) CacheManager.Clear(RetrieveLoginLogsDataKey);
return ret;
}
/// <summary>
/// 查询一个月内所有登录信息
/// </summary>
public static IEnumerable<LoginUser> Retrieves() => CacheManager.GetOrAdd(RetrieveLoginLogsDataKey, key => DbContextManager.Create<LoginUser>().Retrieves());
}
}

View File

@ -1,6 +1,7 @@
using Bootstrap.Security; using Bootstrap.Security;
using Longbow.Cache; using Longbow.Cache;
using Longbow.Data; using Longbow.Data;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Bootstrap.DataAccess namespace Bootstrap.DataAccess
@ -29,7 +30,21 @@ namespace Bootstrap.DataAccess
/// <param name="userName"></param> /// <param name="userName"></param>
/// <param name="password"></param> /// <param name="password"></param>
/// <returns></returns> /// <returns></returns>
public static bool Authenticate(string userName, string password) => DbContextManager.Create<User>().Authenticate(userName, password); public static bool Authenticate(string userName, string password, Action<LoginUser> config)
{
var loginUser = new LoginUser()
{
UserName = userName,
LoginTime = DateTime.Now,
Result = "登录失败"
};
config(loginUser);
if (string.IsNullOrEmpty(loginUser.Ip)) loginUser.Ip = System.Net.IPAddress.IPv6Loopback.ToString();
var ret = DbContextManager.Create<User>().Authenticate(userName, password);
if (ret) loginUser.Result = "登录成功";
LoginHelper.Log(loginUser);
return ret;
}
/// <summary> /// <summary>
/// 查询所有的新注册用户 /// 查询所有的新注册用户

View File

@ -0,0 +1,78 @@
using Longbow;
using Longbow.Configuration;
using PetaPoco;
using System;
using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
/// <summary>
///
/// </summary>
[TableName("LoginLogs")]
public class LoginUser
{
/// <summary>
///
/// </summary>
public string Id { get; set; }
/// <summary>
///
/// </summary>
public string UserName { get; set; }
/// <summary>
///
/// </summary>
public DateTime LoginTime { get; set; }
/// <summary>
///
/// </summary>
public string Ip { get; set; }
/// <summary>
///
/// </summary>
public string Browser { get; set; }
/// <summary>
///
/// </summary>
public string OS { get; set; }
/// <summary>
///
/// </summary>
public string City { get; set; }
/// <summary>
///
/// </summary>
public string Result { get; set; }
/// <summary>
///
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public virtual bool Log(LoginUser user)
{
var db = DbManager.Create();
db.Save(user);
return true;
}
/// <summary>
///
/// </summary>
protected const string KeepLoginLogsPeriodKey = "KeepLoginLogsPeriod";
/// <summary>
///
/// </summary>
/// <returns></returns>
public virtual IEnumerable<LoginUser> Retrieves() => DbManager.Create().Fetch<LoginUser>("Where LoginTime > @0 Order by LoginTime desc", DateTime.Today.AddDays(0 - LgbConvert.ReadValue(ConfigurationManager.AppSettings[KeepLoginLogsPeriodKey], 7)));
}
}

View File

@ -45,7 +45,9 @@ INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [C
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (10, 0, N'站内消息', 100, N'fa fa-envelope', N'~/Admin/Messages', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (10, 0, N'站内消息', 100, N'fa fa-envelope', N'~/Admin/Messages', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (11, 0, N'任务管理', 110, N'fa fa fa-tasks', N'~/Admin/Tasks', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (11, 0, N'任务管理', 110, N'fa fa fa-tasks', N'~/Admin/Tasks', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (12, 0, N'通知管理', 120, N'fa fa-bell', N'~/Admin/Notifications', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (12, 0, N'通知管理', 120, N'fa fa-bell', N'~/Admin/Notifications', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (13, 0, N'系统日志', 130, N'fa fa-gears', N'~/Admin/Logs', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (13, 0, N'日志管理', 130, N'fa fa-gears', N'#', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (20, 13, N'操作日志', 10, N'fa fa-edit', N'~/Admin/Logs', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (21, 13, N'登录日志', 20, N'fa fa-user-circle-o', N'~/Admin/Logins', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, N'在线用户', 140, N'fa fa-users', N'~/Admin/Online', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, N'在线用户', 140, N'fa fa-users', N'~/Admin/Online', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (15, 0, N'程序异常', 150, N'fa fa-cubes', N'~/Admin/Exceptions', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (15, 0, N'程序异常', 150, N'fa fa-cubes', N'~/Admin/Exceptions', N'0')
INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, N'工具集合', 160, N'fa fa-gavel', N'#', N'0') INSERT [dbo].[Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, N'工具集合', 160, N'fa fa-gavel', N'#', N'0')

View File

@ -477,3 +477,33 @@ GO
EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'注册时间' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'RejectUsers', @level2type=N'COLUMN',@level2name=N'RegisterTime' EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'注册时间' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'RejectUsers', @level2type=N'COLUMN',@level2name=N'RegisterTime'
GO GO
/****** Object: Table [dbo].[LoginLogs] Script Date: 03/03/2019 20:05:42 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[LoginLogs](
[ID] [int] IDENTITY(1,1) NOT NULL,
[UserName] [varchar](50) NOT NULL,
[LoginTime] [datetime] NOT NULL,
[Ip] [varchar](15) NOT NULL,
[OS] [varchar](50) NULL,
[Browser] [varchar](50) NULL,
[City] [nvarchar](50) NULL,
[Result] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_LoginLogs] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO

View File

@ -146,15 +146,39 @@
{ {
"_id": ObjectId("5bd7b8445fa31256f77e4b9c"), "_id": ObjectId("5bd7b8445fa31256f77e4b9c"),
"ParentId": "0", "ParentId": "0",
"Name": "系统日志", "Name": "日志管理",
"Order": NumberInt(130), "Order": NumberInt(130),
"Icon": "fa fa-gears", "Icon": "fa fa-gears",
"Url": "#",
"Category": "0",
"Target": "_self",
"IsResource": NumberInt(0),
"Application": "0"
},
{
"_id": ObjectId("5bd9b3d868aa001661776f57"),
"ParentId": "5bd7b8445fa31256f77e4b9c",
"Name": "操作日志",
"Order": NumberInt(10),
"Icon": "fa fa-edit",
"Url": "~/Admin/Logs", "Url": "~/Admin/Logs",
"Category": "0", "Category": "0",
"Target": "_self", "Target": "_self",
"IsResource": NumberInt(0), "IsResource": NumberInt(0),
"Application": "0" "Application": "0"
}, },
{
"_id": ObjectId("5bd9b3d868aa001661776f58"),
"ParentId": "5bd7b8445fa31256f77e4b9c",
"Name": "登录日志",
"Order": NumberInt(20),
"Icon": "fa fa-user-circle-o",
"Url": "~/Admin/Logins",
"Category": "0",
"Target": "_self",
"IsResource": NumberInt(0),
"Application": "0"
},
{ {
"_id": ObjectId("5bd7b8445fa31256f77e4b89"), "_id": ObjectId("5bd7b8445fa31256f77e4b89"),
"ParentId": "0", "ParentId": "0",

View File

@ -42,7 +42,9 @@ INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUE
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (10, 0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0'); INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (10, 0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (11, 0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0'); INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (11, 0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (12, 0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0'); INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (12, 0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (13, 0, '系统日志', 130, 'fa fa-gears', '~/Admin/Logs', '0'); INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (13, 0, '系统日志', 130, 'fa fa-gears', '#', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (20, 13, '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (21, 13, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (14, 0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0'); INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (14, 0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (15, 0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0'); INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (15, 0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0'); INSERT INTO Navigations (ID, ParentId, Name, `Order`, Icon, Url, Category) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0');

View File

@ -147,3 +147,14 @@ CREATE TABLE RejectUsers(
RejectedTime DATETIME NOT NULL, RejectedTime DATETIME NOT NULL,
RejectedReason VARCHAR (50) NULL RejectedReason VARCHAR (50) NULL
); );
CREATE TABLE LoginLogs(
ID INTEGER PRIMARY KEY Auto_increment,
UserName VARCHAR (50) NOT NULL,
LoginTime DATETIME NOT NULL,
Ip VARCHAR NOT NULL,
OS VARCHAR (50) NULL,
Browser VARCHAR (50) NULL,
City VARCHAR (50) NULL,
Result VARCHAR (50) NOT NULL
);

View File

@ -42,7 +42,9 @@ INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '系统日志', 130, 'fa fa-gears', '~/Admin/Logs', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '系统日志', 130, 'fa fa-gears', '#', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 1, 0, '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (currval('navigations_id_seq') - 2, 0, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '工具集合', 160, 'fa fa-gavel', '#', '0'); INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '工具集合', 160, 'fa fa-gavel', '#', '0');

View File

@ -147,3 +147,14 @@ CREATE TABLE RejectUsers(
RejectedTime DATE NOT NULL, RejectedTime DATE NOT NULL,
RejectedReason VARCHAR (50) NULL RejectedReason VARCHAR (50) NULL
); );
CREATE TABLE RejectUsers(
ID SERIAL PRIMARY KEY,
UserName VARCHAR (50) NOT NULL,
LoginTime DATE NOT NULL,
Ip VARCHAR NOT NULL,
OS VARCHAR (50) NULL,
Browser VARCHAR (50) NULL,
City VARCHAR (50) NULL,
Result VARCHAR (50) NOT NULL
);

View File

@ -39,7 +39,9 @@ INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Ca
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (10, 0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (10, 0, '站内消息', 100, 'fa fa-envelope', '~/Admin/Messages', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (11, 0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (11, 0, '任务管理', 110, 'fa fa fa-tasks', '~/Admin/Tasks', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (12, 0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (12, 0, '通知管理', 120, 'fa fa-bell', '~/Admin/Notifications', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (13, 0, '系统日志', 130, 'fa fa-gears', '~/Admin/Logs', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (13, 0, '系统日志', 130, 'fa fa-gears', '#', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (20, 13, '操作日志', 10, 'fa fa-edit', '~/Admin/Logs', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (21, 13, '登录日志', 20, 'fa fa-user-circle-o', '~/Admin/Logins', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (14, 0, '在线用户', 140, 'fa fa-users', '~/Admin/Online', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (15, 0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (15, 0, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0'); INSERT INTO [Navigations] ([ID], [ParentId], [Name], [Order], [Icon], [Url], [Category]) VALUES (16, 0, '工具集合', 160, 'fa fa-gavel', '#', '0');

View File

@ -147,3 +147,14 @@ CREATE TABLE RejectUsers(
[RejectedTime] DATETIME NOT NULL, [RejectedTime] DATETIME NOT NULL,
[RejectedReason] VARCHAR (50) NULL [RejectedReason] VARCHAR (50) NULL
); );
CREATE TABLE LoginLogs(
[ID] INTEGER PRIMARY KEY,
[UserName] VARCHAR (50) NOT NULL COLLATE NOCASE,
[LoginTime] DATETIME NOT NULL,
[Ip] VARCHAR (15) NOT NULL,
[OS] VARCHAR (50) NULL,
[Browser] VARCHAR (50) NULL,
[City] VARCHAR (50) NULL,
[Result] VARCHAR (50) NOT NULL
);

View File

@ -1,4 +1,6 @@
using System.Net.Http; using Bootstrap.DataAccess;
using System.Collections.Generic;
using System.Net.Http;
using Xunit; using Xunit;
namespace Bootstrap.Admin.Api namespace Bootstrap.Admin.Api
@ -7,6 +9,13 @@ namespace Bootstrap.Admin.Api
{ {
public LoginTest(BAWebHost factory) : base(factory, "api/Login") { } public LoginTest(BAWebHost factory) : base(factory, "api/Login") { }
[Fact]
public async void Login_Get()
{
var users = await Client.GetAsJsonAsync<IEnumerable<LoginUser>>();
Assert.NotEmpty(users);
}
[Fact] [Fact]
public async void Login_Ok() public async void Login_Ok()
{ {

View File

@ -14,7 +14,8 @@ namespace Bootstrap.Admin.Controllers
[InlineData("Dicts", "字典表维护")] [InlineData("Dicts", "字典表维护")]
[InlineData("Roles", "角色管理")] [InlineData("Roles", "角色管理")]
[InlineData("Menus", "菜单管理")] [InlineData("Menus", "菜单管理")]
[InlineData("Logs", "系统日志")] [InlineData("Logs", "操作日志")]
[InlineData("Logins", "登录日志")]
[InlineData("FAIcon", "图标集")] [InlineData("FAIcon", "图标集")]
[InlineData("IconView", "图标分类")] [InlineData("IconView", "图标分类")]
[InlineData("Settings", "网站设置")] [InlineData("Settings", "网站设置")]

Binary file not shown.