这是我配置的一部分
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);
}
因此,当我打开/ admin时,我将重定向到/#login。登录对话框打开,登录成功,但是我想重定向到最初请求的URL。
原始URL应该由Spring知道,作为AJAX登录的响应返回,而JavaScript只需更改位置。
同时,我实施了一个对我们非常有效的解决方案。
首先,我创建了一个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。
从Apache的角度来看,myRoot包含我的应用程序的相对根,而不是从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;
}
}
最后一块是Controller,它处理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进行了重定向。
希望这是有用的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句