ASP.NET Identity,持久性 cookie - 是内置的类似的东西吗?

2024-04-20

我们正在使用Cookie身份验证提供者并希望实施'记住账号'我们的应用程序中的功能将像这样工作:

  1. 无论是否'记住账号'复选框是否被选中,令牌过期时间应始终设置为 30 分钟(SlidingExpiration 打开)

  2. 如果用户没有选中“记住我”,我们所做的就是检查令牌是否过期 - 如果过期,则用户将被重定向到登录屏幕(这是内置于 OWIN 中并且工作正常)

  3. 但是,如果用户选中“记住我”,他的凭据应保存在额外的cookie(默认有效期为 30 天)。如果他的令牌过期(超时仍应设置为 30 分钟),OWIN 应使用该附加 cookie 在后台自动更新令牌。换句话说,如果用户选中“记住我”,他应该登录 30 天或直到他注销。

问题是 - 如何使用 OWIN 完成这样的事情?据我所知,默认实现仍然使用过期时间跨度参数 - 唯一的区别是,cookie 被标记为持久性,因此如果用户重新启动浏览器,他就会登录 - 但令牌过期时间仍然受到 ExpireTimeSpan 的限制。

我想我必须以某种方式手动保存用户凭据SignIn并覆盖应用重定向事件(这似乎是未经授权的用户尝试访问需要授权的视图时触发的唯一事件),而不是重定向,而是以某种方式重新生成用户的令牌......但是有人知道到底该怎么做吗?


最后,我最终编写了自定义中间件并将其插入:

RememberMeTokenMiddleware.cs:

using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Security;
using WebApplicationtoRemove.Owin.HelperClasses;
using Microsoft.AspNet.Identity.Owin;

namespace WebApplicationtoRemove.Owin.Middleware
{
    public class RememberMeTokenMiddleware : OwinMiddleware
    {
        #region Private Members

        private static double RememberMeTokenPeriodOfvalidityInMinutes = 43200;

        private IOwinContext Context { get; set; }

        #endregion

        #region Public Static Members



        #endregion

        #region Constructor

        public RememberMeTokenMiddleware(OwinMiddleware next)
            : base(next)
        {
        }

        public RememberMeTokenMiddleware(OwinMiddleware next, double RememberMeTokenPeriodOfvalidityInMinutes)
            : base(next)
        {
            RememberMeTokenMiddleware.RememberMeTokenPeriodOfvalidityInMinutes = RememberMeTokenPeriodOfvalidityInMinutes;
        }

        #endregion

        #region Public Methods

        public override async Task Invoke(IOwinContext context)
        {
            try
            {
                Context = context;

                bool shouldDeleteRememberMeToken = CheckIfRememberMeTokenShouldBeDeleted(context);

                if (shouldDeleteRememberMeToken)
                {
                    context.Response.Cookies.Delete("RemoveRememberMeToken");

                    context.Response.Cookies.Delete("RememberMeToken");
                }
                else
                {
                    if (context.Authentication.User == null || !context.Authentication.User.Identity.IsAuthenticated)
                    {
                        //User is either not set or is not authenticated - try to log him in, using the RememberMeCookie
                        Login(context);
                    }
                }
            }
            catch (Exception ex)
            {
                //Something went wrong - we assume that cookie and/or token was damaged and should be deleted
                context.Response.Cookies.Delete("RememberMeToken");
            }


            await this.Next.Invoke(context);
        }

        #endregion

        #region Static Methods

        /// <summary>
        /// Check conditions and creates RememberMeToken cookie if necessary. This should be called inside SidnedIn event of CookieProvider
        /// </summary>
        public static void CheckAndCreateRememberMeToken(CookieResponseSignedInContext ctx)
        {
            try
            {
                bool signedInFromRememberMeToken = CheckIfUserWasSignedInFromRememberMeToken(ctx.OwinContext);

                if (!signedInFromRememberMeToken && ctx.Properties.IsPersistent)
                {
                    //Login occured using 'normal' path and IsPersistant was set - generate RememberMeToken cookie
                    var claimsToAdd = GenerateSerializableClaimListFromIdentity(ctx.Identity);

                    SerializableClaim cookieExpirationDate = GenerateRememberMeTokenExpirationDateClaim();

                    claimsToAdd.Add(cookieExpirationDate);

                    var allClaimsInFinalCompressedAndProtectedBase64Token = GenerateProtectedAndBase64EncodedClaimsToken(claimsToAdd);

                    ctx.Response.Cookies.Append("RememberMeToken", allClaimsInFinalCompressedAndProtectedBase64Token, new CookieOptions()
                    {
                        Expires = DateTime.Now.AddMinutes(RememberMeTokenPeriodOfvalidityInMinutes)
                    });

                    //Remove the SignedInFromRememberMeToken cookie, to let the middleware know, that user was signed in using normal path
                    ctx.OwinContext.Set("SignedInFromRememberMeToken", false);
                }
            }
            catch (Exception ex)
            {
                //Log errors using your favorite logger here
            }
        }

        /// <summary>
        /// User logged out - sets information (using cookie) for RememberMeTokenMiddleware that RememberMeToken should be removed
        /// </summary>
        public static void Logout(IOwinContext ctx)
        {
            ctx.Response.Cookies.Append("RemoveRememberMeToken", "");
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Returns information if user was signed in from RememberMeToken cookie - this information should be used to determine if RememberMeToken lifetime should be regenerated or not (it should be, if user signed in using normal path)
        /// </summary>
        private static bool CheckIfUserWasSignedInFromRememberMeToken(IOwinContext ctx)
        {
            bool signedInFromRememberMeToken = ctx.Get<bool>("SignedInFromRememberMeToken");

            return signedInFromRememberMeToken;
        }

        /// <summary>
        /// Generates serializable collection of user claims, that will be saved inside the cookie token. Custom class is used because Claim class causes 'Circular Reference Exception.'
        /// </summary>
        private static List<SerializableClaim> GenerateSerializableClaimListFromIdentity(ClaimsIdentity identity)
        {
            var dataToReturn = identity.Claims.Select(x =>
                                new SerializableClaim()
                                {
                                    Type = x.Type,
                                    ValueType = x.ValueType,
                                    Value = x.Value
                                }).ToList();

            return dataToReturn;
        }

        /// <summary>
        /// Generates a special claim containing an expiration date of RememberMeToken cookie. This is necessary because we CANNOT rely on browsers here - since each one threat cookies differently
        /// </summary>
        private static SerializableClaim GenerateRememberMeTokenExpirationDateClaim()
        {
            SerializableClaim cookieExpirationDate = new SerializableClaim()
            {
                Type = "RememberMeTokenExpirationDate",
                Value = DateTime.Now.AddMinutes(RememberMeTokenPeriodOfvalidityInMinutes).ToBinary().ToString()
            };
            return cookieExpirationDate;
        }

        /// <summary>
        /// Generates token containing user claims. The token is compressed, encrypted using machine key and returned as base64 string - this string will be saved inside RememberMeToken cookie
        /// </summary>
        private static string GenerateProtectedAndBase64EncodedClaimsToken(List<SerializableClaim> claimsToAdd)
        {
            var allClaimsAsString = JsonConvert.SerializeObject(claimsToAdd);

            var allClaimsAsBytes = Encoding.UTF8.GetBytes(allClaimsAsString);

            var allClaimsAsCompressedBytes = CompressionHelper.CompressDeflate(allClaimsAsBytes);

            var allClaimsAsCompressedBytesProtected = MachineKey.Protect(allClaimsAsCompressedBytes, "RememberMeToken");

            var allClaimsInFinalCompressedAndProtectedBase64Token = Convert.ToBase64String(allClaimsAsCompressedBytesProtected);

            return allClaimsInFinalCompressedAndProtectedBase64Token;
        }

        /// <summary>
        /// Primary login method
        /// </summary>
        private void Login(IOwinContext context)
        {
            var base64ProtectedCompressedRememberMeTokenBytes = context.Request.Cookies["RememberMeToken"];

            if (!string.IsNullOrEmpty(base64ProtectedCompressedRememberMeTokenBytes))
            {
                var RememberMeToken = GetRememberMeTokenFromData(base64ProtectedCompressedRememberMeTokenBytes);

                var claims = JsonConvert.DeserializeObject<IEnumerable<SerializableClaim>>(RememberMeToken);

                bool isRememberMeTokenStillValid = IsRememberMeTokenStillValid(claims);

                if (isRememberMeTokenStillValid)
                {
                    //Token is still valid - sign in
                    SignInUser(context, claims);

                    //We set information that user was signed in using the RememberMeToken cookie
                    context.Set("SignedInFromRememberMeToken", true);
                }
                else
                {
                    //Token is invalid or expired - we remove unnecessary cookie
                    context.Response.Cookies.Delete("RememberMeToken");
                }
            }
        }

        /// <summary>
        /// We log user, using passed claims
        /// </summary>
        private void SignInUser(IOwinContext context, IEnumerable<SerializableClaim> claims)
        {
            List<Claim> claimList = new List<Claim>();

            foreach (var item in claims)
            {
                string type = item.Type;

                string value = item.Value;

                claimList.Add(new Claim(type, value));
            }

            ClaimsIdentity ci = new ClaimsIdentity(claimList, DefaultAuthenticationTypes.ApplicationCookie);

            context.Authentication.SignIn(ci);

            context.Authentication.User = context.Authentication.AuthenticationResponseGrant.Principal;
        }

        /// <summary>
        /// Get information if RememberMeToken cookie is still valid (checks not only the date, but also some additional information)
        /// </summary>
        private bool IsRememberMeTokenStillValid(IEnumerable<SerializableClaim> claims)
        {
            var userIdClaim = claims.Where(x => x.Type == ClaimTypes.NameIdentifier).SingleOrDefault();

            if (userIdClaim == null)
            {
                throw new Exception("RememberMeTokenAuthMiddleware. Claim of type NameIdentifier was not found.");
            }

            var userSecurityStampClaim = claims.Where(x => x.Type == "AspNet.Identity.SecurityStamp").SingleOrDefault();

            if (userSecurityStampClaim == null)
            {
                throw new Exception("RememberMeTokenAuthMiddleware. Claim of type SecurityStamp was not found.");
            }

            string userId = userIdClaim.Value;

            var userManager = Context.GetUserManager<ApplicationUserManager>();

            if (userManager == null)
            {
                throw new Exception("RememberMeTokenAuthMiddleware. Unable to get UserManager");
            }

            var currentUserData = userManager.FindById(userId);

            if (currentUserData == null)
            {
                return false;
            }

            if (currentUserData.LockoutEndDateUtc >=  DateTime.Now)
            {
                return false;
            }

            if (currentUserData.SecurityStamp != userSecurityStampClaim.Value)
            {
                //User Securitystamp was changed

                return false;
            }

            return GetRememberMeTokenExpirationMinutesLeft(claims) > 0;
        }

        /// <summary>
        /// Returns how many minutes the RememberMeToken will be valid - if it expired, returns zero or negative value
        /// </summary>
        private double GetRememberMeTokenExpirationMinutesLeft(IEnumerable<SerializableClaim> claims)
        {
            double dataToReturn = -1;

            var RememberMeTokenExpirationDate = GetRememberMeTokenExpirationDate(claims);

            dataToReturn = (RememberMeTokenExpirationDate - DateTime.Now).TotalMinutes;

            return dataToReturn;
        }

        /// <summary>
        /// Returns a DateTime object containing the expiration date of the RememberMeToken
        /// </summary>
        private DateTime GetRememberMeTokenExpirationDate(IEnumerable<SerializableClaim> claims)
        {
            DateTime RememberMeTokenExpirationDate = DateTime.Now.AddDays(-1);

            var RememberMeTokenExpirationClaim = GetRememberMeTokenExpirationDateClaim(claims);

            if (RememberMeTokenExpirationClaim == null)
            {
                throw new Exception("RememberMeTokenAuthMiddleware. RememberMeTokenExpirationClaim was not found.");
            }

            long binaryTime = Convert.ToInt64(RememberMeTokenExpirationClaim.Value);

            RememberMeTokenExpirationDate = DateTime.FromBinary(binaryTime);

            return RememberMeTokenExpirationDate;
        }

        /// <summary>
        /// Returns the claim determining the expiration date of the token
        /// </summary>
        private SerializableClaim GetRememberMeTokenExpirationDateClaim(IEnumerable<SerializableClaim> claims)
        {
            var RememberMeTokenExpirationClaim = claims.Where(x => x.Type == "RememberMeTokenExpirationDate").SingleOrDefault();

            return RememberMeTokenExpirationClaim;
        }

        /// <summary>
        /// Attempts to decipher the RememberMeToken to the JSON format containing claims
        /// </summary>
        private string GetRememberMeTokenFromData(string base64ProtectedCompressedRememberMeTokenBytes)
        {
            var protectedCompressedRememberMeTokenBytes = Convert.FromBase64String(base64ProtectedCompressedRememberMeTokenBytes);

            var compressedRememberMeTokenBytes = MachineKey.Unprotect(protectedCompressedRememberMeTokenBytes, "RememberMeToken");

            var RememberMeTokenBytes = CompressionHelper.DecompressDeflate(compressedRememberMeTokenBytes);

            var RememberMeToken = Encoding.UTF8.GetString(RememberMeTokenBytes);

            return RememberMeToken;
        }

        /// <summary>
        /// Returns information if token cookie should be delated (for example, when user click 'Logout')
        /// </summary>
        private bool CheckIfRememberMeTokenShouldBeDeleted(IOwinContext context)
        {
            bool shouldDeleteRememberMeToken = (context.Request.Cookies.Where(x => x.Key == "RemoveRememberMeToken").Count() > 0);

            return shouldDeleteRememberMeToken;
        }

        #endregion
    }
}

还有一些辅助类:压缩助手.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Web;

namespace WebApplicationtoRemove.Owin.HelperClasses
{
    /// <summary>
    /// Data compression helper
    /// </summary>
    public static class CompressionHelper
    {
        public static byte[] CompressDeflate(byte[] data)
        {
            MemoryStream output = new MemoryStream();
            using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal))
            {
                dstream.Write(data, 0, data.Length);
            }
            return output.ToArray();
        }

        public static byte[] DecompressDeflate(byte[] data)
        {
            MemoryStream input = new MemoryStream(data);
            MemoryStream output = new MemoryStream();
            using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
            {
                dstream.CopyTo(output);
            }
            return output.ToArray();
        }
    }
}

SerializedClaim.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplicationtoRemove.Owin.HelperClasses
{
    public class SerializableClaim
    {
        public string Type { get; set; }

        public string ValueType { get; set; }

        public string Value { get; set; }
    }
}

要测试上述内容 - 创建新的 MVC 4.6.x 项目(认证方式:个人用户账户),将上面的类添加进去,然后修改Startup.Auth.cs:

using System;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Google;
using Owin;
using WebApplicationtoRemove.Models;
using WebApplicationtoRemove.Owin.Middleware;

namespace WebApplicationtoRemove
{
    public partial class Startup
    {
        // For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
        public void ConfigureAuth(IAppBuilder app)
        {
            // Configure the db context, user manager and signin manager to use a single instance per request
            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

            // Enable the application to use a cookie to store information for the signed in user
            // and to use a cookie to temporarily store information about a user logging in with a third party login provider
            // Configure the sign in cookie
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    // Enables the application to validate the security stamp when the user logs in.
                    // This is a security feature which is used when you change a password or add an external login to your account.  
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),

                    OnResponseSignedIn = ctx =>
                    {
                        RememberMeTokenMiddleware.CheckAndCreateRememberMeToken(ctx);
                    },

                    OnResponseSignOut = ctx =>
                    {
                        RememberMeTokenMiddleware.Logout(ctx.OwinContext);
                    }
                }
            });

            app.Use<RememberMeTokenMiddleware>();
        }
    }
}

您感兴趣的是:

OnResponseSignedIn = ctx =>
{
    RememberMeTokenMiddleware.CheckAndCreateRememberMeToken(ctx);
},

OnResponseSignOut = ctx =>
{
    RememberMeTokenMiddleware.Logout(ctx.OwinContext);
}

和这一行:

app.Use<RememberMeTokenMiddleware>();

这应该启用中间件。这是如何工作的:如果用户检查 '记住账号' 复选框,一个将创建 RememberMeToken cookie(包含用户在登录期间拥有的所有声明)以及“AspNet.ApplicationCookie”。

当会话超时时,中间件将检查 RememberMeToken 是否存在并且仍然有效- 如果是这样:它将在后台无缝地登录用户。

希望这对任何人都有帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ASP.NET Identity,持久性 cookie - 是内置的类似的东西吗? 的相关文章

  • 传入字典的模型项是类型

    我有一个我理解的错误 但无法找出以正确的方式解决的方法 我有一个 MasterPage 我从该 MasterPage 中调用 标签是一个强类型视图 如下所示 我像这样返回 PartialView return View Tags resul
  • asp.net mvc 4 - 可以在每个线程共享 DbContext 吗?

    From 每个 Web 请求一个 DbContext 为什么 https stackoverflow com questions 10585478 one dbcontext per web request why 我的理解是 DbCont
  • ASP.NET MVC 子操作的路由匹配

    子动作的路由匹配方法与普通动作有什么不同吗 换句话说 子操作是否有一些自动生成的 url 来进行与父操作类似的匹配 父级或子级动作处理没有区别 任何操作都遵循您在中设置的相同路线定义Application Start 这意味着父母的行为以及
  • 构建 ViewModel 的合适粒度是多少?

    我正在开发一个新项目 在看到以前项目的一些困难后 这些项目没有提供足够的视图与模型的分离 特别是使用 MVC 模型和视图开始有点相互渗透 我想使用 MVVM 我了解基本概念 并且很高兴开始使用它 然而 有一件事我有点忽略 ViewModel
  • Yii2 - 错误请求 (#400) |前端和后端cookie

    仅当我打开时才会出现此问题frontend and backend在相同的browser 设想 与后端交互 gt 切换选项卡 gt 与前端交互 gt 切换选项卡返回 gt 与后端交互 gt 错误请求 400 Cookie 后端 identi
  • 将 cookie 设置为在当天结束时过期

    我想设置一个 cookie 并让它在一天结束时过期 这有效 但 24 小时后过期 setcookie route upgrade voted true time 86400 这不起作用 setcookie route upgrade vot
  • Ajax 表单从 Jquery 对话框内重定向页面

    我在部分视图中有一个 jquery 对话框 model JQueryDialogPoc Models FeedBack using Ajax BeginForm GiveFeedback Home null new AjaxOptions
  • Asp.net Identity 注销其他用户

    我正在使用 Asp net Identity 来验证用户身份 并尝试从管理端锁定任何用户 但是当我锁定任何在线用户时 它并没有注销 我读过很多关于我的问题的评论 但它们都不起作用 我尝试使用 UserManager UpdateSecuri
  • 使用 JavaScript 禁用第三方 cookie

    我正在努力根据所有在欧盟运营的公司的数据保护规则实施新的 Cookie 政策合规性 根据该规则 用户在使用任何网站时必须能够拒绝 接受除必需的 Cookie 之外的所有内容 在我客户的网站中 我可以看到正在存储以下第三方 cookie ga
  • 设置 cookie 时中断 JavaScript 执行

    当设置 cookie 时 是否可以始终中断浏览器开发人员工具中的 javascript 执行 无需显式设置 JS 断点 document cookie 在 html head 块的开头添加此代码片段效果很好
  • 包含 ASP.Net Identity 2.0 UserManager.Users.ToListAsync 和 UserManager.FindByIdAsync 上的属性

    我正在尝试实现 Asp Net Identity 2 0 到目前为止 在以下人员的帮助下我做得很好这个博客 http typecastexception com post 2014 06 22 ASPNET Identity 20 Cust
  • SignalR 在子域上协商 404

    我创建了一个小型 MVC SignalR 应用程序 但在子域下的服务器上运行时遇到问题 http chat mydomain com http chat mydomain com 它映射到名为 chat 的文件夹 我还使用 SignalR
  • SSL 和会话劫持/固定

    快问 SSL 是否完全防止会话劫持 固定 谢谢 不可以 例如 在以下情况下可能会发生劫持 被黑客入侵的 CA 根签署无效证书 该证书可用于发起中间人攻击 被黑客攻击的域名所有者电子邮件收件箱使黑客有可能购买经过域名验证的证书 错误的密钥策略
  • 在.NET MVC中,有没有一种简单的方法来检查我是否在主页上?

    如果用户从主页登录 我需要采取特定的操作 在我的 LogOnModel 中 我有一个隐藏字段 Html Hidden returnUrl Request Url AbsoluteUri 在我的控制器中 我需要检查该值是否是主页 在下面的示例
  • orchard cms路由问题

    我创建了一些自定义内容类型 其中包括路线部分 以便我的内容管理员可以编辑项目的别名 我没有运气配置一条路线 使我自己的控制器能够为这些项目的请求提供服务 核心 Routable 模块中到 ItemController 的路径的路由优先级为
  • 如何以一种形式发布两个或多个模型?

    我正在为一个项目开发互联网课程计划应用程序 该课程计划是根据以下模型构建的 使用数据库优先方法中的实体框架生成 public partial class Subject public int Id get set public string
  • 在 Foreach 或 For 循环中使用 EditorFor (ASP.NET MVC + RAZOR)

    我目前正在实施一个家谱我的 ASP NET MVC 项目中的系统 为了设置家庭成员之间的关系 我需要每行显示两个 ComboBox DropDownList 来定义一个成员与另一个成员之间的关系 首先我将分享我的代码 然后我将解释到目前为止
  • 从 MVC 控制器操作调用 javascript

    我可以调用 javascript 函数吗MVC 控制器动作 不是来自视图页面 并获取返回值 如何 我需要向服务器发出请求来自代码 cs 像这里一样使用 javascript 但这是aspx页面 function getInitData va
  • jQuery UI 对话框 + 验证

    我在单击 保存 后使用 Jquery Validate 验证 jQuery UI 对话框时遇到问题 这是我创建 Jquery 对话框的代码 它从目标 href URL 加载对话框 document ready dialogForms fun
  • Jquery 验证不能正确验证数字?

    我在使用 jquery 非侵入式验证验证数字时遇到问题 我使用的版本是 ASP NET MVC 3 jQuery 1 9 1 jQuery 用户界面 1 10 1 JQuery 验证 1 11 0 我试图验证的输入是

随机推荐

  • Visual Studio 2017 不突出显示错误

    我最近从 Visual Studio 2012 升级到 2017 更新到版本 15 3 5 并且 IDE 出现一些问题 在某个项目中 我没有得到错误下划线 在错误列表窗格中 仅构建 实际上显示more比 Build IntelliSense
  • 合并两个具有相同数字键的 PHP 数组[重复]

    这个问题在这里已经有答案了 尝试合并具有相同数字键的两个数组时遇到一些困难 我努力了array merge and array merge recursive 但似乎所做的只是附加第二个数组 第一个数组具有以下形式 Array 384 gt
  • 编辑时更改 NSTextField 边框和 BG 颜色

    我有一个NSTextField显示时不使用边框和窗口背景颜色 但我希望在编辑时将其更改为具有默认边框和白色 BG 颜色 我知道我可以通过以下方式更改这些属性 nameTextField bezeled true nameTextField
  • 加速 solr 索引

    Solr 索引花费的时间太长 我使用的mysql有超过3000万条记录 我正在使用两级子查询 请向我建议索引数据的最佳实践 以便我可以加快该过程 查看Solr性能因素 http wiki apache org solr SolrPerfor
  • java中的验证码[重复]

    这个问题在这里已经有答案了 我想尝试用 Java 开发一个安全登录系统 我应该如何使用 Java 实现 CAPTCHA 我在 Java 中使用的三个验证码库是 JCaptcha 这是三者中最可配置的 并且有很好的文档记录 但无论如何 我们似
  • 使用 HTTPS 链接与 php 方法(file_get_contents、getimagesize)

    当我尝试读取网站中的某些 HTTPS 网址时遇到问题 如果我使用 http 则没有问题 使用file get contents和curl 但是当我用 https 替换 http 时 这些方法不起作用 我收到一些错误 failed to op
  • 调整 R Markdown PDF 文档中文本和块输出之间的间距

    我无法理解如何控制 R Markdown PDF 文档中文本和块输出之间的间距 下面是一个文档的示例 output pdf document setlength lineskip 0pt begin center Random Text e
  • UICollectionView - 在单元格之间画一条线

    如何在 UICollectionView 中的单元格之间绘制一条跨越空间的线 预期的输出是这样的 我所做的最好的事情就是在每个单元格内添加行 如何连接穿过空间的线 我做了一个扩展 你可以像这样使用 collectionView drawLi
  • 使用 Jackson 序列化类型化集合时出错

    我正在尝试使用混合序列化集合 但杰克逊不会保存类型信息 这是一个基本测试 说明会发生什么 public class CollectionSerializationTest interface Common extends Serializa
  • GitHub Actions 使用从 shell 设置的变量

    Goal 在 GitHub Actions 中 从 shell 动态定义我的提交消息 name Commit changes uses EndBug add and commit v7 with message added on date
  • Golang:带有 -> 字符的命令行参数

    我需要接受命令行参数来运行以下格式的 Go 程序 go run app go 1 gt A 我在用os Args 1 但它只接受到 1 gt A 被跳过 非常感谢任何解决此问题的帮助 Thanks 你的 shell 正在解释 gt as I
  • 如何获取时间。立即勾选

    我有一个迭代循环 直到作业启动并运行 ticker time NewTicker time Second 2 defer ticker Stop started time Now for now range ticker C job err
  • 什么更快?循环或多个 if 条件

    我想知道什么更快 是只用一条指令 即 1 1 执行 9 次 for 循环还是执行 9 个 if 条件时 我认为 if 更快 因为您不需要检查循环中的指令 它应该几乎相同 因为for循环本质上是检查if条件为真并运行一段代码 非常类似于if声
  • iOS:如何检测摇动动作?

    我将以下代码添加到我的 appDelegate m void motionBegan UIEventSubtype motion withEvent UIEvent event void motionEnded UIEventSubtype
  • 条件表达式的 raise 语句

    我如何优雅地实现 武士原则 http c2 com cgi wiki SamuraiPrinciple 胜利归来 或者根本不归来 关于我的职能 return
  • Java中一个字符是1字节还是2字节?

    我认为 java 中的字符是 16 位 如建议的那样java doc http download oracle com javase tutorial java nutsandbolts datatypes html 字符串不也是这样吗 我
  • Highcharts Marimekko 图表刷新

    下面的脚本构建了一个基本的 Marimekko 图表 其中 x 值是累积的 作为一种令人兴奋的绘制数据的方式 这是非常棒的 http jsfiddle net Guill84 1o926coh http jsfiddle net Guill
  • 带指针的数组长度

    C 中如何仅使用指针获取数组长度 我知道选项卡名称是指向第一个元素的指针 但下一步是什么 你不能做到 您需要将数组长度与数组指针一起传递 或者需要使用容器对象 例如std vector
  • System.getenv 没有获取 ~/.bash_profile 中定义的变量

    这是文件 bash profile 中的一行 export MESSAGE Hello World 我想访问系统变量MESSAGE在Java中 System getenv MESSAGE 不起作用 bash profile 文件仅源自登录
  • ASP.NET Identity,持久性 cookie - 是内置的类似的东西吗?

    我们正在使用Cookie身份验证提供者并希望实施 记住账号 我们的应用程序中的功能将像这样工作 无论是否 记住账号 复选框是否被选中 令牌过期时间应始终设置为 30 分钟 SlidingExpiration 打开 如果用户没有选中 记住我