diff --git a/Bootstrap.Admin/Controllers/AdminController.cs b/Bootstrap.Admin/Controllers/AdminController.cs
index a4ea5266..3d864ccd 100644
--- a/Bootstrap.Admin/Controllers/AdminController.cs
+++ b/Bootstrap.Admin/Controllers/AdminController.cs
@@ -52,6 +52,12 @@ namespace Bootstrap.Admin.Controllers
///
public ActionResult Logs() => View(new NavigatorBarModel(this));
+ ///
+ ///
+ ///
+ ///
+ public ActionResult Logins() => View(new NavigatorBarModel(this));
+
///
///
///
diff --git a/Bootstrap.Admin/Controllers/Api/LoginController.cs b/Bootstrap.Admin/Controllers/Api/LoginController.cs
index 425a276b..592163b2 100644
--- a/Bootstrap.Admin/Controllers/Api/LoginController.cs
+++ b/Bootstrap.Admin/Controllers/Api/LoginController.cs
@@ -3,6 +3,8 @@ using Bootstrap.Security;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
+using System.Collections.Generic;
+using System.Linq;
namespace Bootstrap.Admin.Controllers.Api
{
@@ -16,6 +18,13 @@ namespace Bootstrap.Admin.Controllers.Api
[ApiController]
public class LoginController : ControllerBase
{
+ ///
+ /// 获得登录历史记录
+ ///
+ ///
+ [HttpGet]
+ public IEnumerable Get() => LoginHelper.Retrieves();
+
///
///
///
diff --git a/Bootstrap.Admin/Views/Admin/Logins.cshtml b/Bootstrap.Admin/Views/Admin/Logins.cshtml
new file mode 100644
index 00000000..3caa048f
--- /dev/null
+++ b/Bootstrap.Admin/Views/Admin/Logins.cshtml
@@ -0,0 +1,29 @@
+@model NavigatorBarModel
+@{
+ ViewBag.Title = "登录日志";
+}
+@section css {
+
+
+
+
+
+
+}
+@section javascript {
+
+
+
+
+
+
+
+
+
+}
+
\ No newline at end of file
diff --git a/Bootstrap.Admin/Views/Admin/Logs.cshtml b/Bootstrap.Admin/Views/Admin/Logs.cshtml
index a93083ea..ca009ff5 100644
--- a/Bootstrap.Admin/Views/Admin/Logs.cshtml
+++ b/Bootstrap.Admin/Views/Admin/Logs.cshtml
@@ -1,6 +1,6 @@
@model NavigatorBarModel
@{
- ViewBag.Title = "系统日志";
+ ViewBag.Title = "操作日志";
}
@section css {
diff --git a/Bootstrap.Admin/appsettings.json b/Bootstrap.Admin/appsettings.json
index 15dbe2ae..276bcdbd 100644
--- a/Bootstrap.Admin/appsettings.json
+++ b/Bootstrap.Admin/appsettings.json
@@ -65,6 +65,7 @@
"KeepExceptionsPeriod": 12,
"KeepLogsPeriod": 12,
"CookieExpiresDays": 7,
+ "KeepLoginLogsPeriod": 7,
"LongbowCache": {
"Enabled": true,
"CorsItems": [
diff --git a/Bootstrap.Admin/wwwroot/js/logins.js b/Bootstrap.Admin/wwwroot/js/logins.js
new file mode 100644
index 00000000..5bb832eb
--- /dev/null
+++ b/Bootstrap.Admin/wwwroot/js/logins.js
@@ -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');
+ });
+});
\ No newline at end of file
diff --git a/Bootstrap.DataAccess.MongoDB/LoginUser.cs b/Bootstrap.DataAccess.MongoDB/LoginUser.cs
index 80859b21..5d46434f 100644
--- a/Bootstrap.DataAccess.MongoDB/LoginUser.cs
+++ b/Bootstrap.DataAccess.MongoDB/LoginUser.cs
@@ -1,4 +1,7 @@
-namespace Bootstrap.DataAccess.MongoDB
+using MongoDB.Driver;
+using System.Collections.Generic;
+
+namespace Bootstrap.DataAccess.MongoDB
{
///
///
@@ -15,5 +18,11 @@
DbManager.LoginUsers.InsertOne(user);
return true;
}
+
+ ///
+ ///
+ ///
+ ///
+ public override IEnumerable Retrieves() => DbManager.LoginUsers.Find(FilterDefinition.Empty).SortByDescending(user => user.LoginTime).ToList();
}
}
diff --git a/Bootstrap.DataAccess/Helper/LoginHelper.cs b/Bootstrap.DataAccess/Helper/LoginHelper.cs
index 31b9e057..20844f2a 100644
--- a/Bootstrap.DataAccess/Helper/LoginHelper.cs
+++ b/Bootstrap.DataAccess/Helper/LoginHelper.cs
@@ -1,4 +1,6 @@
-using Longbow.Data;
+using Longbow.Cache;
+using Longbow.Data;
+using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
@@ -7,11 +9,26 @@ namespace Bootstrap.DataAccess
///
public static class LoginHelper
{
+ ///
+ ///
+ ///
+ public const string RetrieveLoginLogsDataKey = "LoginHelper-Retrieves";
+
///
///
///
///
///
- public static bool Log(LoginUser user) => DbContextManager.Create().Log(user);
+ public static bool Log(LoginUser user)
+ {
+ var ret = DbContextManager.Create().Log(user);
+ if (ret) CacheManager.Clear(RetrieveLoginLogsDataKey);
+ return ret;
+ }
+
+ ///
+ /// 查询一个月内所有登录信息
+ ///
+ public static IEnumerable Retrieves() => CacheManager.GetOrAdd(RetrieveLoginLogsDataKey, key => DbContextManager.Create().Retrieves());
}
}
diff --git a/Bootstrap.DataAccess/LoginUser.cs b/Bootstrap.DataAccess/LoginUser.cs
index 44f159a2..0dc50135 100644
--- a/Bootstrap.DataAccess/LoginUser.cs
+++ b/Bootstrap.DataAccess/LoginUser.cs
@@ -1,5 +1,8 @@
-using PetaPoco;
+using Longbow;
+using Longbow.Configuration;
+using PetaPoco;
using System;
+using System.Collections.Generic;
namespace Bootstrap.DataAccess
{
@@ -60,5 +63,16 @@ namespace Bootstrap.DataAccess
db.Save(user);
return true;
}
+
+ ///
+ ///
+ ///
+ protected const string KeepLoginLogsPeriodKey = "KeepLoginLogsPeriod";
+
+ ///
+ ///
+ ///
+ ///
+ public virtual IEnumerable Retrieves() => DbManager.Create().Fetch("Where LoginTime > @0 Order by LoginTime desc", DateTime.Today.AddDays(0 - LgbConvert.ReadValue(ConfigurationManager.AppSettings[KeepLoginLogsPeriodKey], 7)));
}
}
diff --git a/DatabaseScripts/InitData.sql b/DatabaseScripts/InitData.sql
index 68719da3..9062d4fe 100644
--- a/DatabaseScripts/InitData.sql
+++ b/DatabaseScripts/InitData.sql
@@ -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 (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 (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 (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')
diff --git a/DatabaseScripts/MongoDB/BootstrapAdmin.Navigations.json b/DatabaseScripts/MongoDB/BootstrapAdmin.Navigations.json
index e00a5823..0fd52445 100644
--- a/DatabaseScripts/MongoDB/BootstrapAdmin.Navigations.json
+++ b/DatabaseScripts/MongoDB/BootstrapAdmin.Navigations.json
@@ -146,15 +146,39 @@
{
"_id": ObjectId("5bd7b8445fa31256f77e4b9c"),
"ParentId": "0",
- "Name": "系统日志",
+ "Name": "日志管理",
"Order": NumberInt(130),
"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",
"Category": "0",
"Target": "_self",
"IsResource": NumberInt(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"),
"ParentId": "0",
diff --git a/DatabaseScripts/MySQL/initData.sql b/DatabaseScripts/MySQL/initData.sql
index d02e41e7..f06c3b2d 100644
--- a/DatabaseScripts/MySQL/initData.sql
+++ b/DatabaseScripts/MySQL/initData.sql
@@ -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 (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 (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 (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');
diff --git a/DatabaseScripts/Postgresql/initData.sql b/DatabaseScripts/Postgresql/initData.sql
index abbcc8ab..e9cd5335 100644
--- a/DatabaseScripts/Postgresql/initData.sql
+++ b/DatabaseScripts/Postgresql/initData.sql
@@ -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, '任务管理', 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, '系统日志', 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, '程序异常', 150, 'fa fa-cubes', '~/Admin/Exceptions', '0');
INSERT INTO Navigations (ParentId, Name, "order", Icon, Url, Category) VALUES (0, '工具集合', 160, 'fa fa-gavel', '#', '0');
diff --git a/DatabaseScripts/SQLite/InitData.sql b/DatabaseScripts/SQLite/InitData.sql
index fadaf135..b0137ba0 100644
--- a/DatabaseScripts/SQLite/InitData.sql
+++ b/DatabaseScripts/SQLite/InitData.sql
@@ -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 (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 (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 (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');
diff --git a/UnitTest/Bootstrap.Admin/Api/LoginTest.cs b/UnitTest/Bootstrap.Admin/Api/LoginTest.cs
index 7c275c2a..6e18b793 100644
--- a/UnitTest/Bootstrap.Admin/Api/LoginTest.cs
+++ b/UnitTest/Bootstrap.Admin/Api/LoginTest.cs
@@ -1,4 +1,6 @@
-using System.Net.Http;
+using Bootstrap.DataAccess;
+using System.Collections.Generic;
+using System.Net.Http;
using Xunit;
namespace Bootstrap.Admin.Api
@@ -7,6 +9,13 @@ namespace Bootstrap.Admin.Api
{
public LoginTest(BAWebHost factory) : base(factory, "api/Login") { }
+ [Fact]
+ public async void Login_Get()
+ {
+ var users = await Client.GetAsJsonAsync>();
+ Assert.NotEmpty(users);
+ }
+
[Fact]
public async void Login_Ok()
{
diff --git a/UnitTest/Bootstrap.Admin/Controllers/AdminTest.cs b/UnitTest/Bootstrap.Admin/Controllers/AdminTest.cs
index 80acdc5b..9a58e1cb 100644
--- a/UnitTest/Bootstrap.Admin/Controllers/AdminTest.cs
+++ b/UnitTest/Bootstrap.Admin/Controllers/AdminTest.cs
@@ -14,7 +14,8 @@ namespace Bootstrap.Admin.Controllers
[InlineData("Dicts", "字典表维护")]
[InlineData("Roles", "角色管理")]
[InlineData("Menus", "菜单管理")]
- [InlineData("Logs", "系统日志")]
+ [InlineData("Logs", "操作日志")]
+ [InlineData("Logins", "登录日志")]
[InlineData("FAIcon", "图标集")]
[InlineData("IconView", "图标分类")]
[InlineData("Settings", "网站设置")]