0

我们最近为了一个项目迁移到 cf11 并遇到了一个不寻常的问题:

当用户让他们的会话超时并尝试重新登录时,他们需要两次尝试才能成功登录。

当用户手动注销时,他们登录没有问题。

这个问题在 CF8 中没有发生。我检查了用户范围,看不出有什么不同。我尝试在登录之前添加注销代码,希望我可以使状态相同。两者都没有奏效。这是一个已知问题吗?你对我可以尝试什么有什么建议吗?

编辑:

我在项目的根目录中有一个 Application.cfc 和 result.cfm。我有一个用于未登录页面的 signin/ 文件夹。其中包含处理身份验证的 signin.cfm 和 onsignin.cfm。运行代码时,请等待会话超时,然后再次使用相同的用户名再次登录。

登录/登录.cfm

<form action="onsignin.cfm" method="POST" >
    User name: <input name="login" type="text" />
    <input type="submit" value="Login" name="btnSubmit" >
</form>

登录/onsignin.cfm

<cffunction name="authenticate" access="public" returntype="void">
    <cfargument name="login" />
    <cflogin idletimeout="3600">
        <cfloginuser name="#arguments.login#" password="1234AbCd" roles="admin,developer,login_session,login_signoff" />
    </cflogin>
    <cfreturn />
</cffunction>

<cfscript>
    authenticate(trim(Login));
    writeOutput("At /signin/onsignin.cfm<br/>");
    writeOutput("IsUserLoggedIn: #IsUserLoggedIn()#<br /><hr/>");
</cfscript>

<cflocation url="../result.cfm" addToken="no" /><!--- before we get to result.cfm onRequestStart() in Application.cfc is triggered. --->

应用程序.cfc

<cfcomponent>
    <cfset THIS.Name = "LoginTest" />
    <cfset THIS.SessionManagement = true />
    <cfset THIS.ClientManagement = false />
    <cfset THIS.LoginStorage = "session" />
    <cfset THIS.setClientCookies = false />
    <cfset This.sessiontimeout= createTimeSpan(0,0,0,20)/><!--- 20second timeout to show the session problem --->

    <cffunction name="outputCurrentLoginState" access="private">
        <cfargument name="currentFunction" type="string" required="true"/>
        <cfargument name="TargetPage" type="string" required="true"/>
        <cfscript>
            writeOutput("In function: #arguments.currentFunction# state is <br />");
            writeOutput("TargetPage: #arguments.TargetPage# <br />");
            writeOutput("GetAuthUser: #GetAuthUser()#<br />");
            writeOutput("GetUserRoles: #GetUserRoles()#<br />");
            writedump(session);
            writedump(cookie);
            writeOutput("IsUserLoggedIn: #IsUserLoggedIn()#<br /><hr />");
            /*use writeLog() to view to Console */
        </cfscript>
    </cffunction>

    <cffunction name="OnRequestStart" access="public" returntype="boolean">
        <cfargument name="TargetPage" type="string" required="true"/>
        <cfset outputCurrentLoginState("OnRequestStart",arguments.TargetPage)/>
        <cfif not IsDefined("Cookie.CFID")>
            <CFLOCK SCOPE="SESSION" TYPE="exclusive" TIMEOUT="5">
                <cfcookie name="CFID" value="#SESSION.CFID#" secure="false" httpOnly="true" />
                <cfcookie name="CFTOKEN" value="#SESSION.CFTOKEN#" secure="false" httpOnly="true" />
            </CFLOCK>
        </cfif>
        <cfreturn true />
    </cffunction>

    <cffunction name="OnRequest" access="public">
        <cfargument name="TargetPage" type="string" required="true"/>
        <cfset outputCurrentLoginState("OnRequest",arguments.TargetPage)/>
        <cfif findNoCase("signin/", arguments.TargetPage)>
            <cflogout/>
        </cfif>
        <cfinclude template="#ARGUMENTS.TargetPage#" />
    </cffunction>
</cfcomponent>

结果.cfm

<cfscript>
    writeOutput("GetAuthUser: #GetAuthUser()#<br />");
    writeOutput("GetUserRoles: #GetUserRoles()#<br />");
    writeOutput("--- IsUserLoggedIn: #IsUserLoggedIn()#<br />");
    writeOutput("At /result.cfm<hr/>");
</cfscript>

更新:现在我上面的测试代码在 cf11 上失败了,我在 cf8 服务器上尝试了它,在 cf8 中它按我预期的那样工作。当会话超时时,用户创建新会话没有任何问题。只有在 cf11 中才会失败。

4

3 回答 3

2

我有一个解决方法,对于我的用例来说已经足够了。旧代码:

<cflogin idletimeout="3600">
<cfloginuser name="#yourlogin#" password="#yourpassword#" roles="#yourroles#" />
</cflogin>

新代码:

<cflogin idletimeout="3600" allowconcurrent="false">
<cfloginuser name="#yourlogin##createUUID()#" password="#yourpassword#" roles="#yourroles#" />
</cflogin>

cfloginuser name属性添加随机值应该使每个人都是独一无二的,即使他们在您针对数据库验证他们时使用相同的凭据。这有点骇人听闻,但它解决了这个问题。感谢大家的帮助……尤其是Miguel的接听allowconcurrent

于 2015-03-11T13:24:29.110 回答
2

我在3839458上添加了以下评论:


另一种解决方法是复制 cflogin。例子:

<cflogin ..>
<cflogin ..>

当两者都具有 allowconcurrent=true (默认值)时,两者都将运行。isUserLoggedIn() 在第一次之后返回 YES,但是第一次登录实际上失败了。第二次运行并正确登录。

Repro 附加为 Application.cfc

当 THIS.loginStorage="cookie" 时,如果旧的 cfauthorization cookie 仍然存在,则问题不会再次出现。


谢谢!,

-亚伦

于 2015-05-17T04:51:41.553 回答
1

更新

Adobe 已经针对此问题打开了一个错误 -错误 3839458。我建议您添加您的经验并对该错误进行投票。它目前的状态为“ToTrack”,原因为“PRNeedInfo”。我也投了赞成票,并添加了对此问题的参考以获取更多信息。


从评论中推广

我认为问题在于您已将标签的idletimeout属性设置<cflogin>为比会话超时值(20 秒)长的值(3600 秒)。这不是一个有效的方法。我意识到您已将会话超时设置为 20 秒以便于测试。idletimeout但是,当您设置为时,设置比会话超时时间loginStorage更长是没有意义的session。该<cflogin>标签试图保持用户的会话处于活动状态,但会话本身正在其控制之外被拆除。在我看来,这是自找麻烦。保持idletimeout设置小于或至少等于会话超时设置。

我怀疑您在 ColdFusion 版本之间看到的差异可能与添加到<cflogin>ColdFusion 11 中的标签中的新属性有关。allowconcurrent属性(文档参考)。默认情况下,该设置设置为true意味着应允许并发登录会话。尝试将该属性设置为 false,如<cflogin idletimeout="3600" allowconcurrent="false">. 我相信这将使<cflogin>标签像以前在 ColdFusion 8 中一样工作。

您在评论中提到设置allowconcurrentfalse不是一个可接受的解决方案。为什么?这就是它在 ColdFusion 8 上为您工作的方式。我觉得您所看到的行为是“按设计工作”。但是,如果您认为这是一个错误,请使用 Adob​​e 输入一个错误

顺便说一句,我还注意到您正在设置ClientManagement并且setClientCookies两者都设置为false. 然而,在您的OnRequestStart方法中,您正在设置这些 cookie。为什么?会话管理不需要它们。ColdFusion 服务器将为您处理。

于 2015-03-09T16:41:23.383 回答