diff --git a/FAuth/Controllers/AppController.cs b/FAuth/Controllers/AppController.cs deleted file mode 100644 index a53bd58..0000000 --- a/FAuth/Controllers/AppController.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using FAuth.Models; - -namespace FAuth.Controllers -{ - /// - /// 用户控制器 - /// - public class AppController:ControllerBase - { - public AppController(ILogger logger,IServiceProvider service) : base(logger,service) { - } - - public IActionResult Index() { - return PartialView(); - } - - } -} diff --git a/FAuth/Controllers/ControllerBase.cs b/FAuth/Controllers/ControllerBase.cs index e29dc03..02407a2 100644 --- a/FAuth/Controllers/ControllerBase.cs +++ b/FAuth/Controllers/ControllerBase.cs @@ -1,9 +1,11 @@ using System; using Falcon.Extend; using FAuth.DataBase; +using FAuth.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; namespace FAuth.Controllers { @@ -29,6 +31,10 @@ namespace FAuth.Controllers /// 数据缓冲 /// public ICacheProvider Cache { get; set; } + /// + /// Cookie中定义的键 + /// + public CookieKeyDefine CookieKeys { get; set; } /// /// 通过日志组件和服务集合生成控制器 @@ -40,6 +46,7 @@ namespace FAuth.Controllers this.Services = service; this.Db = service.GetService(); this.Cache = service.GetService(); + this.CookieKeys = Services.GetService>().Value; } } diff --git a/FAuth/Controllers/api/ApiControllerBase.cs b/FAuth/Controllers/api/ApiControllerBase.cs index e09673c..3c225d4 100644 --- a/FAuth/Controllers/api/ApiControllerBase.cs +++ b/FAuth/Controllers/api/ApiControllerBase.cs @@ -1,8 +1,9 @@ using System; +using System.Threading.Tasks; using FAuth.Extensions; using FAuth.Models; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; namespace FAuth.Controllers.api @@ -10,7 +11,9 @@ namespace FAuth.Controllers.api /// /// api控制器基类 /// - [ApiController, Route("api/[Controller]/[Action]")] + [Area("api")] + //[ApiController] + [Route("api/[Controller]/[Action]")] [ServiceFilter(typeof(ApiExceptionFilterAttribute))] [ProducesResponseType(typeof(ApiErrorResult),500)] [ProducesResponseType(typeof(ApiErrorResult),400)] @@ -18,5 +21,9 @@ namespace FAuth.Controllers.api { public ApiControllerBase(ILogger logger,IServiceProvider service) : base(logger,service) { } + + //public override Task OnActionExecutionAsync(ActionExecutingContext context,ActionExecutionDelegate next) { + // return base.OnActionExecutionAsync(context,next); + //} } } diff --git a/FAuth/Controllers/api/AppController.cs b/FAuth/Controllers/api/AppController.cs index a3e5c14..7395501 100644 --- a/FAuth/Controllers/api/AppController.cs +++ b/FAuth/Controllers/api/AppController.cs @@ -1,14 +1,14 @@ using System; -using System.Runtime.InteropServices; -using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Mvc.Routing; -using Microsoft.AspNetCore.Mvc; -using Falcon.Extend; -using FAuth.DataBase; +using System.Collections.Generic; using System.Linq; +using Falcon.Extend; using FAuth.DataBase.Tables; -using Microsoft.EntityFrameworkCore; using FAuth.Extensions; +using FAuth.Extensions.Account; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace FAuth.Controllers.api { @@ -17,7 +17,10 @@ namespace FAuth.Controllers.api /// public class AppController:ApiControllerBase { + public AccountHelper Account { get; set; } + public AppController(ILogger logger,IServiceProvider service) : base(logger,service) { + this.Account = this.Services.GetService(); } /// @@ -81,6 +84,21 @@ namespace FAuth.Controllers.api } } + /// + /// 通过管理员凭据获取应用列表 + /// + /// 管理员凭据 + /// 应用列表 + [HttpGet] + [ProducesResponseType(typeof(IEquatable),200)] + public IEnumerable GetAppList(string adminTicket) { + if(this.Account.IsNotSystemAdmin(adminTicket)) { + throw new ApiException("需要提供管理员票据"); + } + var qu = this.Db.Apps; + return qu.ToList(); + } + } } diff --git a/FAuth/Controllers/api/UserController.cs b/FAuth/Controllers/api/UserController.cs index 5c15773..57daa6b 100644 --- a/FAuth/Controllers/api/UserController.cs +++ b/FAuth/Controllers/api/UserController.cs @@ -89,7 +89,7 @@ namespace FAuth.Controllers.api /// 用户信息 [HttpGet] [ProducesResponseType(typeof(UserInfo),200)] - public UserInfo GetUserByTicket([BindRequired]string ticket) { + public UserInfo GetUserByTicket(string ticket) { if(ticket.IsNullOrEmpty()) { throw new ApiArgumentNullException(nameof(ticket)); } @@ -106,6 +106,7 @@ namespace FAuth.Controllers.api Id = fir.Id, LastLoginDatetime = fir.LastLoginDatetime, UserName = fir.UserName, + Name = fir.Name, }; } diff --git a/FAuth/Controllers/web/AppController.cs b/FAuth/Controllers/web/AppController.cs new file mode 100644 index 0000000..e69de29 diff --git a/FAuth/Controllers/HomeController.cs b/FAuth/Controllers/web/HomeController.cs similarity index 86% rename from FAuth/Controllers/HomeController.cs rename to FAuth/Controllers/web/HomeController.cs index fa5b864..43c136f 100644 --- a/FAuth/Controllers/HomeController.cs +++ b/FAuth/Controllers/web/HomeController.cs @@ -7,12 +7,12 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using FAuth.Models; -namespace FAuth.Controllers +namespace FAuth.Controllers.web { /// /// Home控制器 /// - public class HomeController:ControllerBase + public class HomeController:WebControllerBase { public HomeController(ILogger logger,IServiceProvider service) : base(logger,service) { } diff --git a/FAuth/Controllers/RoleController.cs b/FAuth/Controllers/web/RoleController.cs similarity index 100% rename from FAuth/Controllers/RoleController.cs rename to FAuth/Controllers/web/RoleController.cs diff --git a/FAuth/Controllers/RoleGroupController.cs b/FAuth/Controllers/web/RoleGroupController.cs similarity index 100% rename from FAuth/Controllers/RoleGroupController.cs rename to FAuth/Controllers/web/RoleGroupController.cs diff --git a/FAuth/Controllers/UserController.cs b/FAuth/Controllers/web/UserController.cs similarity index 53% rename from FAuth/Controllers/UserController.cs rename to FAuth/Controllers/web/UserController.cs index ab2e9cc..bf7a717 100644 --- a/FAuth/Controllers/UserController.cs +++ b/FAuth/Controllers/web/UserController.cs @@ -6,13 +6,17 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using FAuth.Models; +using FAuth.Extensions; +using Microsoft.Extensions.DependencyInjection; +using api = FAuth.Controllers.api; +using Falcon.Extend; -namespace FAuth.Controllers +namespace FAuth.Controllers.web { /// /// 用户控制器 /// - public class UserController:ControllerBase + public class UserController:WebControllerBase { public UserController(ILogger logger,IServiceProvider service) : base(logger,service) { } @@ -21,5 +25,12 @@ namespace FAuth.Controllers return PartialView(); } + public IActionResult Login() { + return PartialView(); + } + + public IActionResult ResetPassword() { + return PartialView(); + } } } diff --git a/FAuth/Controllers/web/WebControllerBase.cs b/FAuth/Controllers/web/WebControllerBase.cs new file mode 100644 index 0000000..d1e7356 --- /dev/null +++ b/FAuth/Controllers/web/WebControllerBase.cs @@ -0,0 +1,17 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace FAuth.Controllers.web +{ + /// + /// Web页面控制器基类 + /// + /// + //[Area("web"), Route("web/[Controller]/[Action]")] + public abstract class WebControllerBase:ControllerBase + { + public WebControllerBase(ILogger logger,IServiceProvider service) : base(logger,service) { + } + } +} diff --git a/FAuth/Extensions/CookieHelper.cs b/FAuth/Extensions/CookieHelper.cs new file mode 100644 index 0000000..8737cd3 --- /dev/null +++ b/FAuth/Extensions/CookieHelper.cs @@ -0,0 +1,79 @@ +using System; +using Microsoft.AspNetCore.CookiePolicy; +using Microsoft.AspNetCore.Http; + +namespace FAuth.Extensions +{ + /// + /// cookie帮助类 + /// + public static class CookieHelper + { + /// + /// 设置Cookie值 + /// + /// http上下文 + /// Cookie的键 + /// cookie值 + /// cookie有效期。分钟,无限传null或不传 + public static void SetCookies(this HttpContext httpContext,string key,string value,int? minutes = null) { + SetCookies(httpContext.Response,key,value,minutes); + } + + /// + /// 设置Cookie值 + /// + /// http响应 + /// Cookie的键 + /// cookie值 + /// cookie有效期。分钟,无限传null或不传 + public static void SetCookies(this HttpResponse response,string key,string value,int? minutes = null) { + if(minutes.HasValue) { + response.Cookies.Append(key,value,new CookieOptions { + Expires = DateTime.Now.AddMinutes(minutes.Value) + }); + } else { + response.Cookies.Append(key,value); + } + } + /// + /// 删除cookie + /// + /// http上下文 + /// 要删除的键 + public static void DeleteCookies(this HttpContext httpContext,string key) { + DeleteCookies(httpContext.Response,key); + } + + /// + /// 删除cookie + /// + /// http响应 + /// 要删除的键 + public static void DeleteCookies(this HttpResponse response,string key) { + response.Cookies.Delete(key); + } + /// + /// 获取cookie中的值 + /// + /// http上下文 + /// cookie的键 + /// 保存的值 + public static string GetCookiesValue(this HttpContext httpContext,string key) { + return GetCookiesValue(httpContext.Request,key); + } + + /// + /// 获取cookie中的值 + /// + /// http请求 + /// cookie的键 + /// 保存的值 + public static string GetCookiesValue(this HttpRequest request,string key) { + if(request.Cookies.TryGetValue(key,out string value)) { + return value; + } + return string.Empty; + } + } +} diff --git a/FAuth/FAuth.csproj b/FAuth/FAuth.csproj index 63fcf95..7545f6c 100644 --- a/FAuth/FAuth.csproj +++ b/FAuth/FAuth.csproj @@ -7,6 +7,7 @@ + diff --git a/FAuth/Models/CookieKeyDefine.cs b/FAuth/Models/CookieKeyDefine.cs new file mode 100644 index 0000000..f6cd58c --- /dev/null +++ b/FAuth/Models/CookieKeyDefine.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.Options; + +namespace FAuth.Models +{ + /// + /// Cookie中使用的键定义 + /// + public class CookieKeyDefine:IOptions + { + public CookieKeyDefine Value => this; + + /// + /// 保存用户凭据的键 + /// + public string UserKey { get; set; } = "_userCK"; + } +} diff --git a/FAuth/Models/UserInfo.cs b/FAuth/Models/UserInfo.cs index 96fd4f0..0f05422 100644 --- a/FAuth/Models/UserInfo.cs +++ b/FAuth/Models/UserInfo.cs @@ -19,6 +19,10 @@ namespace FAuth.Models /// public string UserName { get; set; } /// + /// 用户名 + /// + public string Name { get; set; } + /// /// 上次登录时间 /// public DateTimeOffset? LastLoginDatetime { get; set; } diff --git a/FAuth/Startup.cs b/FAuth/Startup.cs index 0ac8944..a579978 100644 --- a/FAuth/Startup.cs +++ b/FAuth/Startup.cs @@ -7,6 +7,7 @@ using FAuth.DataBase; using FAuth.Extensions; using FAuth.Extensions.Account; using FAuth.Extensions.Decryptor; +using FAuth.Models; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; @@ -85,6 +86,8 @@ namespace FAuth services.AddUserTicketDryptor(UTDO); //עapi services.AddScoped(); + //עCookie + services.Configure(this.Configuration.GetSection("CookieKeyDefine")); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. diff --git a/FAuth/Views/Home/Index.cshtml b/FAuth/Views/Home/Index.cshtml index 640d685..3d0b1f6 100644 --- a/FAuth/Views/Home/Index.cshtml +++ b/FAuth/Views/Home/Index.cshtml @@ -1,5 +1,5 @@ @{ - ViewBag.Title = "首页"; + ViewBag.Title = "统一登录平台"; }
diff --git a/FAuth/Views/Shared/_Layout.cshtml b/FAuth/Views/Shared/_Layout.cshtml index 0f19801..5f0e4bd 100644 --- a/FAuth/Views/Shared/_Layout.cshtml +++ b/FAuth/Views/Shared/_Layout.cshtml @@ -1,4 +1,6 @@ - +@using Microsoft.Extensions.Options +@inject IOptions CKD + @@ -30,8 +32,21 @@ +
+
+
+ 登录 +
+
+ 欢迎: + 修改密码 + 退出 +
+
@@ -47,9 +62,58 @@ + + @RenderSection("Scripts",required: false) diff --git a/FAuth/Views/User/Login.cshtml b/FAuth/Views/User/Login.cshtml new file mode 100644 index 0000000..de0dc05 --- /dev/null +++ b/FAuth/Views/User/Login.cshtml @@ -0,0 +1,22 @@ +@inject IOptions CKD + +
+
+ + + + +
+
+ \ No newline at end of file diff --git a/FAuth/Views/User/ResetPassword.cshtml b/FAuth/Views/User/ResetPassword.cshtml new file mode 100644 index 0000000..28cc22e --- /dev/null +++ b/FAuth/Views/User/ResetPassword.cshtml @@ -0,0 +1,28 @@ + +
+ + + + +
+ + \ No newline at end of file diff --git a/FAuth/Views/_ViewImports.cshtml b/FAuth/Views/_ViewImports.cshtml index c2e2b46..d9bad0d 100644 --- a/FAuth/Views/_ViewImports.cshtml +++ b/FAuth/Views/_ViewImports.cshtml @@ -1,4 +1,5 @@ @using FAuth @using FAuth.Models +@using Microsoft.Extensions.Options @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper FAuth.Extensions.TagHelpers.*, FAuth \ No newline at end of file diff --git a/FAuth/wwwroot/js/site.js b/FAuth/wwwroot/js/site.js index b2f58e1..f27f501 100644 --- a/FAuth/wwwroot/js/site.js +++ b/FAuth/wwwroot/js/site.js @@ -2,3 +2,44 @@ // for details on configuring this project to bundle and minify static web assets. // Write your JavaScript code. + +var myJs = {}; +myJs.get = function (url, data, success, error) { + $.ajax({ + url: url, + type: "get", + data: data, + success: function (d) { + success(d); + }, + error: function (d) { + error(d.status, d.responseJSON.Id, d.responseJSON.Message) + }, + }); +} +myJs.post = function (url, data, success, error) { + $.ajax({ + url: url, + type: "post", + data: data, + success: function (d) { + success(d); + }, + error: function (d) { + error(d.status, d.responseJSON.Id, d.responseJSON.Message) + }, + }); +} +myJs.msg = function (msg) { + alert(msg); +} +//保存用户凭据的键,在_layout视图设置 +myJs.userKey = ""; +//获取登录的用户票据 +myJs.getTicket = function () { + return $.cookie(myJs.userKey); +} +//移除用户登录票据 +myJs.removeTicket = function () { + $.removeCookie(myJs.userKey); +} \ No newline at end of file diff --git a/FAuth/wwwroot/lib/jquery.cookie/jquery.cookie-1.4.1.min.js b/FAuth/wwwroot/lib/jquery.cookie/jquery.cookie-1.4.1.min.js new file mode 100644 index 0000000..c0f19d8 --- /dev/null +++ b/FAuth/wwwroot/lib/jquery.cookie/jquery.cookie-1.4.1.min.js @@ -0,0 +1,2 @@ +/*! jquery.cookie v1.4.1 | MIT */ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}}); \ No newline at end of file diff --git a/FAuth/wwwroot/lib/jquery.cookie/jquery.cookie.js b/FAuth/wwwroot/lib/jquery.cookie/jquery.cookie.js new file mode 100644 index 0000000..c7f3a59 --- /dev/null +++ b/FAuth/wwwroot/lib/jquery.cookie/jquery.cookie.js @@ -0,0 +1,117 @@ +/*! + * jQuery Cookie Plugin v1.4.1 + * https://github.com/carhartl/jquery-cookie + * + * Copyright 2013 Klaus Hartl + * Released under the MIT license + */ +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // CommonJS + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + + var pluses = /\+/g; + + function encode(s) { + return config.raw ? s : encodeURIComponent(s); + } + + function decode(s) { + return config.raw ? s : decodeURIComponent(s); + } + + function stringifyCookieValue(value) { + return encode(config.json ? JSON.stringify(value) : String(value)); + } + + function parseCookieValue(s) { + if (s.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape... + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + + try { + // Replace server-side written pluses with spaces. + // If we can't decode the cookie, ignore it, it's unusable. + // If we can't parse the cookie, ignore it, it's unusable. + s = decodeURIComponent(s.replace(pluses, ' ')); + return config.json ? JSON.parse(s) : s; + } catch(e) {} + } + + function read(s, converter) { + var value = config.raw ? s : parseCookieValue(s); + return $.isFunction(converter) ? converter(value) : value; + } + + var config = $.cookie = function (key, value, options) { + + // Write + + if (value !== undefined && !$.isFunction(value)) { + options = $.extend({}, config.defaults, options); + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setTime(+t + days * 864e+5); + } + + return (document.cookie = [ + encode(key), '=', stringifyCookieValue(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // Read + + var result = key ? undefined : {}; + + // To prevent the for loop in the first place assign an empty array + // in case there are no cookies at all. Also prevents odd result when + // calling $.cookie(). + var cookies = document.cookie ? document.cookie.split('; ') : []; + + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + var name = decode(parts.shift()); + var cookie = parts.join('='); + + if (key && key === name) { + // If second argument (value) is a function it's a converter... + result = read(cookie, value); + break; + } + + // Prevent storing a cookie that we couldn't decode. + if (!key && (cookie = read(cookie)) !== undefined) { + result[name] = cookie; + } + } + + return result; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) === undefined) { + return false; + } + + // Must not alter options, thus extending a fresh object... + $.cookie(key, '', $.extend({}, options, { expires: -1 })); + return !$.cookie(key); + }; + +}));