Spring Boot + GraphQL API 实战:使用 React 和 Auth0 构建安全数据平台

作者:API传播员 · 2025-10-22 · 阅读时间:7分钟
本教程详细介绍了如何使用Spring Boot和Spring for GraphQL构建GraphQL API,以查询Neo4j数据库中的数据。同时,展示了如何通过React客户端和MUI数据网格消费该API,并使用Auth0进行身份验证。内容包括项目初始化、GraphQL架构定义、领域模型创建、Repository和Controller的构建,以及React客户端的开发和Auth0的集成。

一. 介绍 GraphQL 与项目概览

GraphQL 是一种用于 API 的查询语言和运行时环境。它允许客户端精确获取所需数据,而无需依赖服务器预定义的响应。与传统 REST API 需要多个 URL 获取数据不同,GraphQL API 可以通过对象间引用在单一响应中返回所有相关数据。

本教程演示如何使用 Spring BootSpring for GraphQL 构建 GraphQL API,查询 Neo4j 数据库中的公司、人员和属性信息。同时,我们将展示如何使用 Next.jsMUI 数据网格 构建 React 客户端,并通过 Auth0 提供身份验证。


二. 使用 Spring Boot 构建 GraphQL API

1. 初始化 Spring Boot 项目

创建资源服务器项目,通过 Spring for GraphQL 提供 GraphQL API,并使用 Spring Data Neo4j 查询数据库。

使用 Spring Initializr 创建项目:

https start.spring.io/starter.zip \
  bootVersion==3.2.1 \
  language==java \
  packaging==jar \
  javaVersion==17 \
  type==gradle-project \
  dependencies==data-neo4j,graphql,docker-compose,web \
  groupId==com.okta.developer \
  artifactId==spring-graphql \
  name=="Spring Boot API" \
  description=="Demo project of a Spring Boot GraphQL API" \
  packageName==com.okta.developer.demo > spring-graphql-api.zip

解压后,在 src/main/resources/graphql 下创建 schema.graphqls 文件定义 API 架构:

type Query {
  companyList(page: Int): [Company!]!
  companyCount: Int
}

type Company {
  id: ID
  SIC: String
  category: String
  companyNumber: String
  countryOfOrigin: String
  incorporationDate: String
  mortgagesOutstanding: Int
  name: String
  status: String
  controlledBy: [Person!]!
  owners: [Property!]!
}

type Person {
  id: ID
  birthMonth: String
  birthYear: String
  nationality: String
  name: String
  countryOfResidence: String
}

type Property {
  id: ID
  address: String
  county: String
  district: String
  titleNumber: String
}

2. 定义领域模型

src/main/java/com/okta/developer/demo/domain 下创建实体类:

a. Person 类

package com.okta.developer.demo.domain;

import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;

@Node
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String birthMonth;
    private String birthYear;
    private String countryOfResidence;
    private String name;
    private String nationality;
    // 构造函数、getter 和 setter
}

b. Property 类

package com.okta.developer.demo.domain;

import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;

@Node
public class Property {
    @Id
    @GeneratedValue
    private Long id;
    private String address;
    private String county;
    private String district;
    private String titleNumber;
    // 构造函数、getter 和 setter
}

c. Company 类

package com.okta.developer.demo.domain;

import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Node
public class Company {
    @Id
    @GeneratedValue
    private Long id;
    private String SIC;
    private String category;
    private String companyNumber;
    private String countryOfOrigin;
    private LocalDate incorporationDate;
    private Integer mortgagesOutstanding;
    private String name;
    private String status;

    @Relationship(type = "HAS_CONTROL", direction = Relationship.Direction.INCOMING)
    private List<Person> controlledBy = new ArrayList<>();

    private List<Property> owns = new ArrayList<>();
    // 构造函数、getter 和 setter
}

3. 创建 Repository 和 Controller

a. CompanyRepository

package com.okta.developer.demo.repository;

import com.okta.developer.demo.domain.Company;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;

public interface CompanyRepository extends ReactiveNeo4jRepository<Company, Long> {}

b. CompanyController

package com.okta.developer.demo.controller;

import com.okta.developer.demo.domain.Company;
import com.okta.developer.demo.repository.CompanyRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Controller
public class CompanyController {
    @Autowired
    private CompanyRepository companyRepository;

    @QueryMapping
    public Flux<Company> companyList(@Argument Long page) {
        return companyRepository.findAll().skip(page * 10).take(10);
    }

    @QueryMapping
    public Mono<Long> companyCount() {
        return companyRepository.count();
    }
}

三. 构建 React 客户端

1. 初始化 Next.js 项目

npx create-next-app@latest react-graphql
cd react-graphql
npm install @mui/x-data-grid @mui/material @emotion/react @emotion/styled axios

2. 创建 API 客户端

src/services/base.tsx

import axios from 'axios';

export const backendAPI = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_SERVER_URL,
});

export default backendAPI;

src/services/companies.tsx

import { backendAPI } from './base';

export const CompanyApi = {
  getCompanyList: async (page: number) => {
    const response = await backendAPI.post('/graphql', {
      query: { companyList(page: ${page}) { id name category } },
    });
    return response.data.data.companyList;
  },
};

3. 创建数据表组件

src/components/company/CompanyTable.tsx

import { DataGrid } from '@mui/x-data-grid';

const CompanyTable = ({ rows, columns }) => {
  return <DataGrid rows={rows} columns={columns} />;
};

export default CompanyTable;

四. 使用 Auth0 添加安全性

1. 配置 Auth0

Auth0 创建应用,获取客户端 ID 和域名,并添加到 .env.local

NEXT_PUBLIC_AUTH0_DOMAIN=
NEXT_PUBLIC_AUTH0_CLIENT_ID=

2. 集成 Auth0 到 React

安装 Auth0 React SDK:

npm install @auth0/auth0-react

src/components/authentication/Auth0ProviderWithNavigate.tsx

import { Auth0Provider } from '@auth0/auth0-react';

const Auth0ProviderWithNavigate = ({ children }) => {
  const domain = process.env.NEXT_PUBLIC_AUTH0_DOMAIN;
  const clientId = process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID;

  return (
    <Auth0Provider domain={domain} clientId={clientId} authorizationParams={{ redirect_uri: window.location.origin }}>
      {children}
    </Auth0Provider>
  );
};

export default Auth0ProviderWithNavigate;

五. 总结

通过本教程,您学会了如何:

  • 使用 Spring Boot 构建 GraphQL API
  • 使用 Next.jsMUI 构建 React 客户端
  • 使用 Auth0 实现身份验证

GraphQL 的灵活查询能力允许客户端快速调整数据请求,而 Auth0 提供安全、便捷的身份验证机制,使应用程序既高效又安全。

原文链接: https://auth0.com/blog/how-to-build-a-graphql-api-with-spring-boot/