简体   繁体   English

登录后重定向回页面

[英]Redirect back to a page after a login

I'm doing a simple forum with a series of Servlets that each represent a home, topic, postedit, login and userlist page. 我正在用一系列Servlets做一个简单的论坛,每个Servlets代表一个家,主题,发布,登录和用户列表页面。 On some of these pages there is a link that appears when a user isn't logged in. 在其中一些页面上,当用户未登录时会显示一个链接。

What I'd like to achieve is to trigger a redirection (using forward() on a RequestDispatcher) after a login so the browser goes back to the page where a user was before clicking the login link. 我想要实现的是在登录后触发重定向(在RequestDispatcher上使用forward()),以便浏览器在单击登录链接之前返回用户所在的页面。 In order to do this, I see two solutions. 为了做到这一点,我看到两个解决方案。

The first solution is to have an HTML Form with a login button and an invisible field that will contain information that will say what page to redirect as a Parameter . 第一个解决方案是使用一个带有登录按钮和不可见字段的HTML Form ,该字段将包含将要重定向为Parameter页面的信息。 This is doable but I'd like to try something else. 这是可行的,但我想尝试其他的东西。

The second solution is to add an Attribute to the session that represents the first "page" in some way. 第二种解决方案是在session中添加一个Attribute ,以某种方式表示第一个“页面”。 This could contain a String but this is no different from the first approach. 这可能包含一个String,但这与第一种方法没有什么不同。 Another twist would be to add a reference to the HttpServlet and to use instanceof or a static String variable that could be used to identify the Servlet in some way. 另一个转折是添加对HttpServlet的引用并使用instanceof或静态String变量,该变量可用于以某种方式标识Servlet。 However, this would require creating a common ancestor class for all the Servlets . 但是,这需要为所有Servlets创建一个共同的祖先类。

Perhaps there is another simple solution that you can see that would form a good compromise ? 或许有另一个简单的解决方案,你可以看到,这将形成一个良好的妥协? Or, maybe one of the above solutions is perfectly acceptable ? 或者,上述解决方案中的一种可能完全可以接受?

I would prefer the first above the second solution. 我更喜欢第二个解决方案之上的第一个。 This is request scoped information and really doesn't belong in the session, it would only lead to "wtf?" 这是请求范围的信息,实际上不属于会话,它只会导致“wtf?” experiences when you have multiple windows/tabs open in the same session. 在同一会话中打开多个窗口/选项卡时的体验。

On the link to the login page, just pass the current URL as request parameter: 在登录页面的链接上,只需将当前URL作为请求参数传递:

<a href="/login?from=${pageContext.request.requestURI}">Login</a>

Or if it is a POST form to the login page: 或者,如果它是登录页面的POST表单:

<input type="hidden" name="from" value="${pageContext.request.requestURI}">

In the login form, transfer it to the next request as hidden variable: 在登录表单中,将其作为隐藏变量传输到下一个请求:

<input type="hidden" name="from" value="${param.from}">

In the login servlet, make use of it: 在登录servlet中,使用它:

User user = userDAO.find(username, password);
if (user != null) {
    request.getSession().setAttribute("user", user);
    response.sendRedirect(request.getParameter("from"));
} else {
    // Show error.
}

Fairly simple, isn't it? 相当简单,不是吗? :) :)

Some may suggest to use request.getHeader("referer") for this inside the login form instead of request.getRequestURI() in the link/button before login, but I wouldn't do that as this is client-controlled and doesn't always return reliable information. 有些人可能会建议在登录表单中使用request.getHeader("referer") ,而不是在登录前使用链接/按钮中的request.getRequestURI() ,但是我不这样做,因为这是客户端控制的并且没有总是返回可靠的信息。 Some clients have disabled it or are using some software which spoofes it with an invalid value, such as most of the ( cough ) Symantec products do. 有些客户已经禁用它或正在使用某些软件,这些软件使用无效值来欺骗它,例如大多数( 咳嗽 )赛门铁克产品都会这样做。

Your first suggested approach is the best one. 您的第一个建议的方法是最好的方法。 Have a hidden field with value=request.getRequestURI() and redirect to that URI after login. 拥有一个带有value=request.getRequestURI()的隐藏字段,并在登录后重定向到该URI。

Using referer won't work, because IE (at least some of its versions) doesn't set the referer header. 使用referer将无法工作,因为IE(至少某些版本)不设置referer标头。

Storing a parameter in the session would cause strange behaviour if the user opens multiple tabs. 如果用户打开多个选项卡,则在会话中存储参数会导致奇怪的行为。

Edit: To illustrate the question better: 编辑:更好地说明问题:

some resource -> (requests protected resource) -> (gets forwarded to the login page) -> (should be redirected to the original resource)

Most answers assume that a "login" link/button is clicked, and then the login page is opened. 大多数答案都假设单击“登录”链接/按钮,然后打开登录页面。 This is only one side of the story. 这只是故事的一个方面。 In that case the original resource URL can be added as a parameter, and placed in the login form (in a hidden field). 在这种情况下,原始资源URL可以作为参数添加,并放在登录表单中(在隐藏字段中)。

But in case of forwarding from a protected resource to the login page, the hidden field should contain the immediate request URL. 但是,如果从受保护资源转发到登录页面,隐藏字段应包含即时请求URL。

This, of course, isn't what's in the question, but will eventually arise as a situation and should be considered as well. 当然,这不是问题所在,但最终会出现这种情况,也应该加以考虑。

If you want to do this with pages, your login page could look at the referer (sic) header in the request that loaded it ( request.getHeader("referer") ) to see if that's a page on your site (if not -- or if the header is missing -- use a default of some kind). 如果你想用页面做这个,你的登录页面可以查看加载它的请求中的referer(sic)标题( request.getHeader("referer") ),看看你的网站上是否有页面(如果不是 - - 或者如果标题丢失 - 使用某种默认值)。 Then it would store that URL (I'd probably use a hidden field, as you said, in the login form; but a session var would work too). 然后它会存储该URL(我可能会使用隐藏字段,如您所说,在登录表单中;但会话var也可以使用)。 When the login is complete, issue a redirect to the stored URL. 登录完成后,发出重定向到存储的URL。

These days, I'd probably use all of that as a fallback mechanism if I couldn't do the login by overlaying a dialog on the page and logging in via Ajax -- and so, never leaving the page at all. 这些天,如果我无法通过在页面上覆盖对话框并通过Ajax登录来进行登录,我可能会将所有这些用作回退机制 - 所以,永远不要离开页面。


Edit Or better yet, as Bozho points out, encode the target page into your link to the login page. 编辑或者更好的是,正如Bozho指出的那样,将目标页面编码为您登录页面的链接。 Although it's not true that IE doesn't set the "referer" header (it does), referer is not required and can be disabled, and since you're already dynamically creating the page linking to the login form, why be vulnerable to that if you don't need to be. 虽然IE不设置“referer”标题(确实如此) 并不是真的,但是不需要referer并且可以禁用referer,并且由于你已经动态创建链接到登录表单的页面,为什么容易受到攻击如果你不需要。

from: http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity.pdf 来自: http//static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity.pdf

chapter: Application Flow on Authentication Success and Failure 章:认证成功和失败的应用流程

... If authentication is successful, the resulting Authentication object will be placed into the SecurityContextHolder. ...如果身份验证成功,生成的身份验证对象将被放入SecurityContextHolder。 The configured AuthenticationSuccessHandler will then be called to either redirect or forward the user to the approprate destination. 然后将调用配置的AuthenticationSuccessHandler以将用户重定向或转发到适当的目标。 By default a SavedRequestAwareAuthenticationSuccessHandler is used, which means that the user will be redirected to the original destination they requested before they were asked to login. 默认情况下,使用SavedRequestAwareAuthenticationSuccessHandler,这意味着在要求用户登录之前,用户将被重定向到他们请求的原始目标。 ... ...

Using the hidden field in the form is pretty standard. 使用表单中的隐藏字段非常标准。 Why try reinventing the wheel? 为什么尝试重新发明轮子?

Ok, here's what I've done. 好的,这就是我所做的。 Login is a two-step process with one Servlet showing aa form and another controlling if the username+password combination is correct. 登录是一个两步过程,一个Servlet显示一个表单,另一个控制用户名+密码组合是否正确。 The two could be combined. 这两者可以结合起来。

A parameter can be sent through a form or through a link (JSP hasn't been added yet): 参数可以通过表单或链接发送(尚未添加JSP):

out.println( "Login <a href='LoginServlet?comeback=home'>here</a><br>" );  

The parameter is then retrieved as follows: 然后按如下方式检索参数:

String comeback = request.getParameter("comeback");

Once the login information has been checked, redirection can be done as follows: 检查登录信息后,可以按如下方式完成重定向:

RequestDispatcher rd = request.getRequestDispatcher( redirectionPath );

if( rd != null )
   rd.forward(request, response);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM