XSRF - 如何设置跨域cookie

7
我开发了REST API和两个JavaScript客户端(单页应用程序和基于electron的本地应用程序)。在这两个客户端中,我的用户通过OAuth2流程进行身份验证:
  1. 将用户密码发送到服务器
  2. 获取访问令牌(以纯文本形式)和刷新令牌(在httponly cookie中)
  3. 当令牌过期时,发送请求到/refresh端点进行刷新(服务器从cookie读取refresh_token)
现在我想要实现csrf保护。因此,我在后端(Spring)上实现了它。
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
                .authorizeRequests().antMatchers("/", "/index.html", "/token/**").permitAll()
                .anyRequest().authenticated();
    }

我的SPA运行得非常完美,Angular从cookie中读取XSRF-TOKEN并将其发送到X-XSRF-TOKEN头中。但是我在Electron应用程序中遇到了问题。它无法访问cookie(因为来自不同源 - Electron正在运行 file:// url),因此无法设置X-XSRF-TOKEN头。

我该如何解决这个问题?是否有任何方法可以实例化“跨源”cookie?或者我可以通过Electron魔术Electron API以某种方式获取cookie值(如果它可以访问文件系统,那么它可能可以访问在计算机上创建的任何cookie)?

1个回答

0

我曾经遇到过同样的问题,最终通过实现一个 Angular HTTP 拦截器来解决它,像这样:

@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {

  constructor(private tokenExtractor: HttpXsrfTokenExtractor, //from angular
              private nativeAuthService: NativeAuthService) { //my native service
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    //this works in web
    const headerName = 'X-XSRF-TOKEN';
    const token = this.tokenExtractor.getToken() as string;
    if (token !== null && !req.headers.has(headerName)) {
      req = req.clone({ headers: req.headers.set(headerName, token) });
      return next.handle(req);
    }

    //this works in electron
    return this.nativeAuthService.getCookieValue('XSRF-TOKEN').pipe(
      mergeMap((xsrfToken: string) => {
        if (xsrfToken && !req.headers.has(headerName)) {
          req = req.clone({ headers: req.headers.set(headerName, xsrfToken) });
        }
        return next.handle(req);
      }),
    );
  }
}

而我的nativeAuthService基本上只是在electron主进程中调用了这个方法:

export function getCookieValue(cookieName: string): Observable<string> {
  return from(session.defaultSession.cookies.get({ name: cookieName })
    .then((cookies: Electron.Cookie[]) => {
      if (cookies.length == 1) {
        return cookies[0].value;
      } else {
        if (cookies.length > 1) {
          throw Error(`There is more than one cookie with the name: ${ cookieName }.`);
        }
        return '';
      }
    }));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接