前后端分离下的跨域CAS请求
最重要的两点:
- ajax请求跨域的时候,默认不会携带cookie。
- 请求分为普通请求(HttpRequest)和Ajax请求(XMLHttpRequest)
先屡一下跨域CAS认证的流程:
前端发起ajax请求,请求首先被跨域Filter过滤,加上Access-Control-Allow-Origin , 然后再被CASFilter过滤,此时没有登录的用户会被重定向到cas.host.cn/login进行登录,最最最关键的地方就在这里。
通常是这样的:前端发起HttpRequest,后端接受请求并执行res.sendRedirect(),前端接受相应并发起HttpRequest,请求重定向后的页面,其中HttpRequest不存在跨域问题。
但是现在是这样的:前端发起XMLHttpRequest, 后端接受请求并执行res.sendRedirect(),前端接受相应并发起XMLHttpRequest,请求重定向后的页面,但是,由于cas.host.cn/login没有配置跨域(安全上也不允许),所以产生了跨域!
解决思路:
思路就是把XMLHttpRequest替换为HttpRequest
方案:
@Path("admin/auth") public class AuthController { private static Properties prop = new Properties(); static { InputStream in = CORSFilter.class.getClassLoader().getResourceAsStream("dev.properties"); try { prop.load(in); } catch (IOException e) { e.printStackTrace(); } } @Get("validate") public String validate(Invocation inv) throws JSONException { HttpServletRequest request = inv.getRequest(); Assertion assertion = (Assertion) request.getSession().getAttribute("_const_cas_assertion_"); JSONObject result = new JSONObject(); if (assertion == null || assertion.getPrincipal().getName() == null) { result.put("success",false); result.put("data", prop.getProperty("cas.server.url") + "/login?service=" + prop.getProperty("server.url") + "/thoth-admin/admin/auth/redirect"); } else { result.put("success", true); } return "@json:" + result.toString(); } @Get("redirect") public void redirect(Invocation inv) throws IOException { inv.getResponse().sendRedirect(prop.getProperty("server.url")+"/thoth-admin/admin"); } }
用户每次发起ajax请求之前,先请求validate接口,检验当前用户的cookie是否失效,如果没有,就返回{success: true},前端则继续发送接下来的ajax请求。
如果失效了,就返回一个字符串,内容是将要跳转的cas验证地址,前端则手动通过location.href = "这个地址"来进行HttpRequest。cas登录成功后,会再次重定向,重定向的地址是service=后面的地址。
另外,需要注意的一点是跨域Filter优先级必须要高于CASFIlter,否则请求会先被CASFilter过滤,没有登录过得用户会被302跳转到cas.mioffice.cn/login, 但是事实是你连跳转的机会都没有就会被浏览器告知你跨域了。
因为你的请求还没有被跨域Filter过滤,此时响应头里还没有Access-Control-Allow-Origin。