2015-12-02 24 views
0

這是我的配置彈簧4 Ajax登陸重定向到請求的URL

public class CustomWebSecurityConfigurer extends WebSecurityConfigurerAdapter { 
    private static final String LOGIN_URL = "/#login"; 
    @Override 
    protected void configure(final HttpSecurity http) throws Exception { 
     final String adminAccess = String.format("hasAnyRole('ROLE_%s', 'ROLE_%s')", 
       Role.SYSTEM_ADMINISTRATOR, Role.USER_ADMINISTRATOR); 
     http.authorizeRequests().antMatchers("/admin/**").access(adminAccess).and().formLogin() 
       .loginPage(LOGIN_URL); 
    } 
} 

的一部分,人們可以看到,登錄只是觸發起始頁面,#login用來顯示一個模式登錄對話,發送使用AJAX登錄。

以下代碼是登錄名。

@RequestMapping(value = "/login", method = RequestMethod.POST) 
ResponseEntity<Map<String, Object>> login(@RequestBody final JSONCredentials credentials) { 
    log.debug("Test: {}", requestCache == null ? "null" : requestCache.getClass()); 
    final Authentication auth = new UsernamePasswordAuthenticationToken(credentials.getUsername(), 
      credentials.getPassword()); 
    final Authentication authenticated = authenticationManager.authenticate(auth); 
    if (authenticated.isAuthenticated()) { 
     SecurityContextHolder.getContext().setAuthentication(authenticated); 
     return get(); 
    } 
    SecurityContextHolder.clearContext(); 
    throw new BadCredentialsException(""); 
} 

它執行身份驗證並調用get方法。

@RequestMapping(method = RequestMethod.GET) 
ResponseEntity<Map<String, Object>> get() { 
    final Map<String, Object> result = new HashMap<>(); 
    final Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
    if (auth != null) { 
     result.put("principal", auth.getPrincipal()); 
    } 
    result.put("redirectTo", "URL where I come from"); 
    return ResponseEntity.ok(result); 
} 

所以當我打開/管理我重定向到/#登錄。登錄對話框打開,登錄成功,但我喜歡重定向到最初請求的URL。
原始URL應該由Spring知道,作爲AJAX登錄的響應返回,並且JavaScript應該改變位置。

回答

0

在此期間,我實施了一個對我們非常有效的解決方案。

首先,我創建了一個AccessFilter,用於檢查是否發生了到配置的登錄URL的重定向。

public class AccessFilter extends OncePerRequestFilter { 
    private static final Logger log = LoggerFactory.getLogger(AccessFilter.class); 

    @Inject private SessionContext ctx; 
    @Inject private Environment env; 

    @Override 
    protected void doFilterInternal(final HttpServletRequest request, 
      final HttpServletResponse response, final FilterChain filterChain) 
      throws ServletException, IOException { 
     filterChain.doFilter(request, response); 
     if (response.getStatus() == 302 && response.getHeaderNames().contains("Location") 
       && response.getHeader("Location").contains("#login")) { 
      final String vrkroot = env.getProperty("VRK_HOST_NAME"); 
      final String myRoot = vrkroot.replaceAll("^https?://.+?/", "/"); 
      final String redirect = myRoot + request.getServletPath().replaceFirst("/", "") 
        + (request.getQueryString() != null ? "?" + request.getQueryString() : ""); 
      log.debug("URL: {}, Query: {}, Redirect: {}", request.getRequestURL().toString(), 
        request.getQueryString(), redirect); 
      ctx.setAfterLoginRedirect(redirect); 
     } 
    } 
} 

環境變量VRK_HOST_NAME用於定義系統正在使用的實際URL。這是必要的,因爲Tomcat 8服務器位於重定向到Tomcat上下文的Apache Web服務器之後。

http://www.mydomain.de/ > localhost:8080/<ContextRoot> 

我發現沒有其他簡單的方法來確定實際的URL。

myRoot包含我從Apache的角度來看應用程序的相對根目錄,而不是Tomcat點。這隻適用於我的應用不在根目錄中的情況。 MyAppName可以與ContextRoot不同。

http://www.mydomain.de/MyAppName 

最後,重定向URL被計算並存儲在上下文對象/變量中。

@Component 
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) 
public class SessionContext implements Serializable { 
    private static final long serialVersionUID = -8618385704526830047L; 
    private String afterLoginRedirect; 

    public String getAfterLoginRedirect() { 
     return afterLoginRedirect; 
    } 

    public void setAfterLoginRedirect(final String afterLoginRedirect) { 
     this.afterLoginRedirect = afterLoginRedirect; 
    } 
} 

最後一塊是處理AJAX登錄的控制器。

@RequestMapping(value = "/login", method = RequestMethod.POST) 
ResponseEntity<Map<String, Object>> login(@RequestBody final JSONCredentials credentials) { 
    final Authentication auth = new UsernamePasswordAuthenticationToken(credentials.getUsername(), 
      credentials.getPassword()); 
    final Authentication authenticated = authenticationManager.authenticate(auth); 
    if (authenticated.isAuthenticated()) { 
     SecurityContextHolder.getContext().setAuthentication(authenticated); 
     return get(); 
    } 
    SecurityContextHolder.clearContext(); 
    throw new BadCredentialsException(""); 
} 

@RequestMapping(method = RequestMethod.GET) 
ResponseEntity<Map<String, Object>> get() { 
    final Map<String, Object> result = new HashMap<>(); 
    final Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
    final HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder 
      .getRequestAttributes()).getRequest(); 
    final CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); 
    final HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder 
      .getRequestAttributes()).getResponse(); 
    response.addHeader("X-CSRF-TOKEN", csrfToken.getToken()); 
    if (auth != null) { 
     result.put("principal", auth.getPrincipal()); 
     if (!Strings.isNullOrEmpty(ctx.getAfterLoginRedirect())) { 
      result.put("redirectTo", ctx.getAfterLoginRedirect()); 
      ctx.setAfterLoginRedirect(null); 
     } 
    } 
    return ResponseEntity.ok(result); 
} 

這在控制器會做的登錄名和返回是我此刻誰的信息這兩種方法。在get方法中,重定向URL被髮送到客戶端,最終JavaScript正在執行重定向。

希望這是有用的。