0%

CAS 解决前后端分离静态页面地址无法验证,无法登录的问题

简介

现有项目采用前后端分离分开部署的策略,根据前文CAS客户端和Gateway集成的文章中提到的CAS的验证流程,我们可得知在用户调用接口时如果发现本地项目没有缓存用户登录信息,就跳转到CAS服务端去验证,登录完成后再跳转到原页面,并在url中带上ticket参数再去验证本次请求的合法性,在采用前后端分离的项目中会有一下问题,以下是解决方案.

验证ticket参数无法获取

因为是前后端分离项目,在调用接口时发现本地没有缓存登录信息,将跳转到统一登录页面,登录完成后再调回到原有页面的地址,并在url中加入ticket参数,由于我们采用的是前后端分离的策略,此时回调的地址是一个静态页面,那么后端无法自动对ticket参数进行验证,所以我这里采取了一个策略,在调用接口发现本地没有缓存用户信息的时候,不是直接跳转到cas登录页,而是跳转到一个已经集成了cas客户端第三方的应用(我这里是网关),由网关将需要跳转的链接组装好(将cas登录后跳转的地址改到网关),在登录完成后跳转到网关进行ticket合法调用的验证(因为网关已经集成客户端)并且缓存下登录信息,在ticket验证成功后再从新跳转到静态页面。注意我们在获取原有静态访问页面地址的时候不是直接获取url,而是优先获取请求头中的Referer中的地址,如果没有Referer再去获取调用接口的rul地址,因为前端中经常使用异步去调用接口,如果直接获取请求接口的url中的地址,我们得到的地址是接口的地址如以下代码,而Referer地址则是反应了请求时从哪里跳转过来的,具体可自行百度Referer

  • 获取登录成功后跳转回原有页面的地址

    1
    2
    StringUtils.isEmpty(request.getHeaders().getFirst("Referer")) ?
    serviceUrl : request.getHeaders().getFirst("Referer"),
  • 在gateway拦截器中,如果没有登录成功则返回对象告诉页面跳转的地址

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //这里直接返回对象,这里个返回时放在认证拦截器中,如果没有登录返回301和跳转地址供前端跳转,urlToRedirect的格式举例为
    //http://localhost.com/cas/login?service=192.168.1.1/gateway/validateTicket&redirectUrl=192.168.1.2/redirect
    //在原有的service参数后又自定义一个redirectUrl参数,供在ticket验证完成后跳转到访问静态页面
    public static Mono<Void> createResponse(ServerWebExchange exchange ,String urlToRedirect){
    ServerHttpResponse response = exchange.getResponse();
    JSONObject responseJson = new JSONObject();
    responseJson.put("code","301");
    responseJson.put("urlToRedirect",urlToRedirect);
    byte[] bits = responseJson.toJSONString().getBytes(StandardCharsets.UTF_8);
    DataBuffer buffer = response.bufferFactory().wrap(bits);
    return response.writeWith(Mono.just(buffer));
    }
  • gateway中重定向的拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class RedirectFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpRequest request =exchange.getRequest();
    String uri=exchange.getRequest().getURI().toString();
    if(uri.contains("/redirect") && uri.contains("redirectUrl=")){
    //如果是重定向的话
    String redirectUrl=request.getQueryParams().getFirst("redirectUrl");
    return GatewayCommonUtils.redirect(exchange, redirectUrl);
    }else {//如果不是重定向url的话跳过拦截器
    return chain.filter(exchange);
    }

    }

    @Override
    public int getOrder() {
    return 10000;
    }
    }

异步调用问题

采取前后端分离,前端调用接口必然大量存在异步调用,而最开始时我采用的是后端发起301重定向,由浏览器去自动完成跳转,但是在异步情况下,浏览器无法对后端发起的30X请求发起定向,于是这我采用如上代码,直接返回对象和跳转url给前端,由前端去跳转,而不是再由后端发起重定向.

跨域保存cookie的问题

在登录成功后需要在本地项目中保存登录信息,由于我们项目使用的是gateway作为网关接入客户单,gateway中并没有session的概念,于是我采用cookie来保存登录的凭证,再用登录凭证去redis中查找登录的信息来判断用户是否已经登录过,但是这样存在一个问题,用户信息是在网关中验证的,我在网关中设置的cookie写入路径path为 / ,但是采用前后端分离的情况静态页面有着单独的http地址,并没有和网关在同一个域,这样导致了我在网关写入的cookie信息无法在前端的那个域中调用的接口中获取到,我这里采用的方法是统一有nginx反向代理网关域名和http静态页面的域名,强制让网关和静态页面在同一个域下,解决跨域无法读取cookie的问题