Spring Security:如何将重定向查询参数添加到登录URL以允许页面添加书签? [英] Spring Security: How to add a redirect query parameter to the login url to allow bookmarking of the page?

查看:208
本文介绍了Spring Security:如何将重定向查询参数添加到登录URL以允许页面添加书签?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题场景

我目前正在处理我的应用程序的登录页面,该页面基于Spring启动和相关的Spring项目(像安全和云)。我希望我的应用程序的用户为登录页面添加书签,因此需要采取这种行为。当我开始考虑潜在的问题时,我认为在您为页面添加书签后应用程序将无法知道重定向到哪里(因为这可能是多个URL)(因为只有/ login并且没有重定向所以)。通常,用户不会,例如,/ dashboard被重定向到登录,因为不存在身份验证。在使用呈现他或她的凭证之后,应用程序重定向用户。但这是唯一可能的原因,即应用程序在当前会话中持有SavedRequest,告知重定向位置。

I'm currently working on the login page of my application which is based on Spring boot and related Spring projects (like security and cloud). I expect the users of my application to bookmark the login page and thus need to act of this behavior. As I started thinking about potential problems I figured that the application would not be able to know where to redirect to (since this can be multiple urls) after you bookmark the page (since there is only /login and no redirect what so ever). Normally the user would not to, for example, /dashboard and gets redirected to login cause there is no authentication present. After the use presents his or her credentials the application redirect the user. But that's only possible cause the application holds a SavedRequest in his current session telling the redirect location.

我想要实现的目标

基本上我想要实现的是应用程序在用户在/ login url上设置书签后知道去哪里。这里理想的情况是/ login url包含重定向参数。例如。

Basically what I want to achieve is for the application to know where to go to after the user has set a bookmark on the /login url. The ideal situation here would be for the /login url to contain a redirect parameter. For example.


  1. 用户访问/仪表板?param = value

  2. 不存在身份验证,应用程序重定向to / login?redirect = / dashboard?param = value

  3. 用户登录

  4. 应用程序将用户发送到/dashboard?param=value.

  1. User visits /dashboard?param=value
  2. No authentication present, Application redirects to /login?redirect=/dashboard?param=value
  3. User logs in
  4. Application sends user to /dashboard?param=value.

现在,如果用户将为步骤2中提供的URL添加书签,则在一段时间后单击书签时,将为应用程序提供足够的信息做出合理的重定向。

Now if the user would bookmark the url served in step 2, then upon clicking the bookmark after some time, would supply the application with enough information to make a sensible redirect.

如果有人知道更好的方法,我想听听。

In case someone knows a better approach I'd like to hear it.

到目前为止所采取的步骤

到目前为止,我的搜索基于关于 StackOverflow的另一个答案的解决方案。这似乎是朝着正确方向迈出的一步,但仍然缺少一些所需的功能。

Until now I've based my search for a solution on another answer on StackOverflow. It seems like a step in the right direction but some of the desired functionality is still missing.

我首先创建了LoginUrlAuthenticationEntryPoint类的Custom实现。它会覆盖begin方法,如下所示:

I started out by creating a Custom implementation of the LoginUrlAuthenticationEntryPoint class. It overrides the commence method, which looks like this:

public class CustomLoginUrlAuthenticaitonEntryPoint extends LoginUrlAuthenticationEntryPoint 
{
  @Override
  public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException 
  {
    if (!request.getRequestURI().equals(this.getLoginFormUrl())) 
    {
      RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
      redirectStrategy.sendRedirect(request, response, getLoginFormUrl() + "?redirect=" + request.getRequestURI() + "?" + request.getQueryString());
    }
  }
}

然后我添加了这个自定义类到HttpSecurity作为默认的身份验证入口点。

Then I added this custom class to the HttpSecurity as the default authentication entry point.

@Configuration
@Order(-20)
public class SecurityConfig extends WebSecurityConfigurerAdapter 
{
  @Override
  protected void configure(HttpSecurity http) throws Exception 
  {
    http
      .formLogin()
        .loginPage("/login")
        .permitAll()
      .and()
        .exceptionHandling()
        .authenticationEntryPoint(new CustomLoginUrlAuthenticationEntryPoint("/login"));
  }
}

最后我实现了一个自定义登录控制器来服务器登录页面。

And last I implemented a custom login controller to server the Login page.

@Controller
public class LoginController 
{
  @RequestMapping(value = "/login", method = RequestMethod.GET)
  public ModelAndView login(@RequestParam(value = "redirect", required = false) String redirect) 
  {
    ModelAndView model = new ModelAndView();
    // Do something with the redirect url;
    model.setViewName("login");
    return model;
  }

但是一旦我实现了这一点,似乎重定向工作正常。 (/ dashboard?param = value被重定向到/ login?redirect = / dashboard?param = value)但是登录页面没有显示。但是当直接访问/ login url时,登录页面会显示。

But once I implemented this it seemed that the redirect was working correctly. (/dashboard?param=value was redirected to /login?redirect=/dashboard?param=value) but the login page was not showing. But when visiting the /login url directly the login page does show.

所以我认为我是在为/ login网址添加自定义查询参数的正确位置,但我认为实施并不完全。有人可以帮我解决问题,或者为我的问题提供更好的解决方案吗?

So I think I'm in the right place for adding a custom query parameter to the /login url, but the implementation is not quite complete I guess. Can someone help me figure things out, or maybe supply a better solution for my problem?

提前致谢。

推荐答案

警告:使用参数确定重定向到的位置可以打开您的应用程序,直到打开重定向漏洞。根据用户输入执行重定向时要非常小心。

WARNING: Using a parameter to determine where you are redirecting to can open your application up to Open Redirect Vulnerabilities. Be very cautions when performing redirects based upon user input.

ContinueEntryPoint

您的第一步是创建一个 AuthenticationEntryPoint ,它负责在显示登录表单时包含一个URL参数,以便在URL中继续。在这个例子中,我们将使用参数名称continue。

Your first step is to create an AuthenticationEntryPoint which is in charge of including a parameter with the URL to continue to in the URL when displaying the log in form. In this example, we will use the parameter name continue.

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.web.util.UriComponentsBuilder;

/**
 * @author Rob Winch
 *
 */
public class ContinueEntryPoint extends LoginUrlAuthenticationEntryPoint {

    public ContinueEntryPoint(String loginFormUrl) {
        super(loginFormUrl);
    }

    @Override
    protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) {

        String continueParamValue = UrlUtils.buildRequestUrl(request);
        String redirect = super.determineUrlToUseForThisRequest(request, response, exception);
        return UriComponentsBuilder.fromPath(redirect).queryParam("continue", continueParamValue).toUriString();
    }
}

WebSecurityConfig

下一步是包含使用ContinueEntryPoint的安全配置。例如:

The next step is to include a Security configuration that uses the ContinueEntryPoint. For example:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .exceptionHandling()
                .authenticationEntryPoint(new ContinueEntryPoint("/login"))
                .and()
            .authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin();
    }
}

LoginController

最后,如果用户已经过身份验证,您应该创建一个重定向到参数的LoginController。例如:

Finally, you should create a LoginController that redirects to the parameter if the user is already authenticated. For example:

import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.NotBlank;

public class RedirectModel {
    @Pattern(regexp="^/([^/].*)?$")
    @NotBlank
    private String continueUrl;

    public void setContinue(String continueUrl) {
        this.continueUrl = continueUrl;
    }

    public String getContinue() {
        return continueUrl;
    }
}

@Controller
public class LoginController {

    @RequestMapping("/login")
    public String login(Principal principal, @Valid @ModelAttribute RedirectModel model, BindingResult result) {
        if (!result.hasErrors() && principal != null) {
            // do not redirect for absolute URLs (i.e. https://evil.com)
            // do not redirect if we are not authenticated
            return "redirect:" + model.getContinue();
        }
        return "login";
    }
}

完整样本

您可以在 rwinch / spring-security-sample 在so-34087954-continue-on-login分支中。您可以轻松下载它如果你不想使用git。

You can find a complete sample in github at rwinch/spring-security-sample in the so-34087954-continue-on-login branch. You can easily download it if you prefer not to use git.

这篇关于Spring Security:如何将重定向查询参数添加到登录URL以允许页面添加书签?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆