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

ada*_*shr 18 java spring-security

这是我的spring安全配置:

<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>
Run Code Online (Sandbox Code Playgroud)

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

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

我也尝试了以下但是Principal对象总是null,大概是因为security="none"属性再次.

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

    return "login";
}
Run Code Online (Sandbox Code Playgroud)

Xae*_*ess 9

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

Spring Security不知道您的应用程序的内部(即,如果您希望根据用户是否登录而使您的登录页面变为flex).要在登录页面被请求并且用户已登录时显示您的主页,请使用SecurityContextHolder登录页面(或其控制器)中的用户并将用户重定向或转发到主页.

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

applicationContext-security.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>
Run Code Online (Sandbox Code Playgroud)

添加到applicationContext.xml bean定义:

<bean id="securityContextAccessor"
    class="com.example.spring.security.SecurityContextAccessorImpl" />
Run Code Online (Sandbox Code Playgroud)

这是班级

public final class SecurityContextAccessorImpl
      implements SecurityContextAccessor {

  @Autowired
  private AuthenticationTrustResolver authenticationTrustResolver;

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

实现简单的界面

public interface SecurityContextAccessor {
  boolean isCurrentAuthenticationAnonymous();
}
Run Code Online (Sandbox Code Playgroud)

(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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

定义defaultTargetUrlString bean看起来像是一个hack,但我没有更好的方法来硬编码url ...(实际上在我们的项目中,我们使用<util:constant>包含静态最终String字段的类.)但它毕竟是有效的.


dtr*_*unk 7

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

<access-denied-handler ref="accessDeniedHandler" />
<intercept-url pattern="/auth/login" access="ROLE_ANONYMOUS" />
Run Code Online (Sandbox Code Playgroud)

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

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)