如果用户登录后访问登录页面,如何重定向到主页?

2022-09-02 21:53:45

这是我的弹簧安全配置:

<http pattern="/auth/login" security="none" />
<http pattern="/auth/loginFailed" security="none" />
<http pattern="/resources/**" security="none" />

<http auto-config="true" access-decision-manager-ref="accessDecisionManager">
    <intercept-url pattern="/auth/logout" access="permitAll"/>
    <intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS"/>
    <intercept-url pattern="/**" access="XYZ_ACCESS"/>

    <form-login
        login-page="/auth/login"
        authentication-failure-url="/auth/loginFailed"
        authentication-success-handler-ref="authenticationSuccessHandler" />
    <logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>

扩展了确保用户被重定向到他最初请求的页面。authenticationSuccessHandlerSavedRequestAwareAuthenticationSuccessHandler

但是,由于被标记为,如果用户在登录后访问登录页面,我无法成功将用户重定向到主页。我相信这也是正确的用户体验/auth/loginsecurity="none"

我也尝试了下面,但对象总是,大概是因为属性再次出现。Principalnullsecurity="none"

@RequestMapping(value = "/auth/login", method = GET)
public String showLoginForm(HttpServletRequest request, Principal principal) {
    if(principal != null) {
        return "redirect:/";
    }

    return "login";
}

答案 1

我比上次更深入地检查了该主题,发现您必须确定用户是否由您自己在控制器中进行身份验证。Row Winch (Spring Security dev) 在这里说

Spring Security不了解您的应用程序的内部(即,如果您想根据用户是否登录来灵活设置登录页面)。要在请求登录页且用户登录时显示您的主页,请使用登录页(或其控制器)中的 ,并将用户重定向或转发到主页。SecurityContextHolder

因此,解决方案是确定用户请求是否是匿名的,如下所示。/auth/login

应用程序上下文安全.xml

<http auto-config="true" use-expressions="true"
        access-decision-manager-ref="accessDecisionManager">
    <intercept-url pattern="/auth/login" access="permitAll" />
    <intercept-url pattern="/auth/logout" access="permitAll" />
    <intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS" />
    <intercept-url pattern="/**" access="XYZ_ACCESS" />

    <form-login login-page="/auth/login"
        authentication-failure-url="/auth/loginFailed"
        authentication-success-handler-ref="authenticationSuccessHandler" />
    <logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>

<beans:bean id="defaultTargetUrl" class="java.lang.String">
    <beans:constructor-arg value="/content" />
</beans:bean>

<beans:bean id="authenticationTrustResolver"
        class="org.springframework.security.authentication.AuthenticationTrustResolverImpl" />

<beans:bean id="authenticationSuccessHandler"
        class="com.example.spring.security.MyAuthenticationSuccessHandler">
    <beans:property name="defaultTargetUrl" ref="defaultTargetUrl" />
</beans:bean>

添加到应用程序上下文.xml bean 定义:

<bean id="securityContextAccessor"
    class="com.example.spring.security.SecurityContextAccessorImpl" />

这是类

public final class SecurityContextAccessorImpl
      implements SecurityContextAccessor {

  @Autowired
  private AuthenticationTrustResolver authenticationTrustResolver;

  @Override
  public boolean isCurrentAuthenticationAnonymous() {
    final Authentication authentication =
        SecurityContextHolder.getContext().getAuthentication();
    return authenticationTrustResolver.isAnonymous(authentication);
  }
}

实现简单接口

public interface SecurityContextAccessor {
  boolean isCurrentAuthenticationAnonymous();
}

(SecurityContextHolder访问代码与控制器分离,我遵循了这个答案的建议,因此是接口。SecurityContextAccessor

最后但并非最不重要的一点是控制器中的重定向逻辑:

@Controller
@RequestMapping("/auth")
public class AuthController {
  @Autowired
  SecurityContextAccessor securityContextAccessor;

  @Autowired
  @Qualifier("defaultTargetUrl")
  private String defaultTargetUrl;

  @RequestMapping(value = "/login", method = RequestMethod.GET)
  public String login() {
    if (securityContextAccessor.isCurrentAuthenticationAnonymous()) {
      return "login";
    } else {
      return "redirect:" + defaultTargetUrl;
    }
  }
}

定义字符串bean似乎是一个黑客,但我没有更好的方法来不硬编码url...(实际上,在我们的项目中,我们使用<util:constant>,类包含静态的最终字符串字段。但它毕竟有效。defaultTargetUrl


答案 2

您还可以将登录页面限制为并设置:ROLE_ANONYMOUS<access-denied-handler />

<access-denied-handler ref="accessDeniedHandler" />
<intercept-url pattern="/auth/login" access="ROLE_ANONYMOUS" />

在您的处理程序中检查用户是否已通过身份验证:

@Service
public class AccessDeniedHandler extends AccessDeniedHandlerImpl {
    private final String HOME_PAGE = "/index.html";

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && !(auth instanceof AnonymousAuthenticationToken)) {
            response.sendRedirect(HOME_PAGE);
        }

        super.handle(request, response, e);
    }
}

推荐