OAuth 2.0 规范总结
تم الإنشاء في: ١٨ يناير ٢٠٢٥
تم الإنشاء في: ١٨ يناير ٢٠٢٥
Gathering normative documents
I’m systematically compiling key RFCs for OAuth 2.0, covering core specifications, bearer tokens, PKCE, JWT profiles, and introspection.
Focusing on key documents
I’m identifying pivotal RFCs for OAuth 2.0: core authorization, bearer tokens, dynamic client registration, introspection, token revocation, JWT, PKCE, and device authorization grant.
Thought about OAuth 2.0规范,持续 4 秒
在 IETF 制定的 OAuth 2.0 生态中,最核心、最具规范性的文档都以 RFC(Request for Comments)形式发布。除了最基本的 OAuth 2.0 核心协议(即 RFC 6749、RFC 6750),围绕它还有众多扩展及补充规范,用于支持不同场景、功能和安全要求。下面列出主要的规范性文档(大多都可以在 IETF 的官方网站 或 tools.ietf.org 上查阅):
RFC 6749: The OAuth 2.0 Authorization Framework
RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage
RFC 7009: OAuth 2.0 Token Revocation
RFC 7636: Proof Key for Code Exchange by OAuth Public Clients (PKCE)
RFC 7662: OAuth 2.0 Token Introspection
RFC 7008 (草案阶段) 等其他安全增强
RFC 7591: OAuth 2.0 Dynamic Client Registration Protocol
RFC 7592: OAuth 2.0 Dynamic Client Registration Management Protocol
RFC 8628: OAuth 2.0 Device Authorization Grant (Device Flow)
RFC 8252: OAuth 2.0 for Native Apps (BCP 212)
RFC 8707: Resource Indicators for OAuth 2.0
RFC 7519: JSON Web Token (JWT)
RFC 7523: JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants
IETF OAuth 2.0 相关 Working Group
除了正式发布的 RFC 外,OAuth 工作组还有一些草案文档(Draft),通常涵盖更前沿的应用场景和安全最佳实践。可以在 IETF Datatracker 中关注相关进展。
各大云服务或社交平台的实现
如 Google、微软、GitHub、微信企业号等在各自开发者文档中,都有遵循(或部分遵循)OAuth 2.0 规范的实现说明。有时还会结合一些私有扩展。
开发者社区与官方示例
OAuth 2.0 并不是只由单一文档定义的,而是由一系列 RFC 文档所构成的一个“框架+扩展”生态系统。其中最核心的规范是 RFC 6749(核心框架)和 RFC 6750(Bearer Token 使用)。围绕这两个核心,又有许多扩展规范,为不同的业务场景(如设备模式、动态注册、令牌格式、身份层扩展等)提供了可选的规范性指导。
如果你想系统了解 OAuth 2.0 的整体规范,可以从如下路径入手:
希望对你了解和使用 OAuth 2.0 的“规范性”部分有所帮助。
Mapping authorization flows
I'm piecing together the OAuth server implementation, focusing on authorization and token request endpoints. This involves outlining typical fields and their formats in requests and responses, considering both standard and PKCE scenarios.
Thought about OAuth 2.0 server字段,持续 9 秒
下面的说明主要基于 OAuth 2.0 核心规范(RFC 6749、RFC 6750) 和常见的实践(包括 PKCE、Refresh Token 等)进行整理,给出在开发 OAuth 2.0 授权服务器时“各步骤常见字段”和“它们的典型格式、单位或约定”。不同厂商或框架可能会在此基础上增加一些私有扩展字段,这里仅列出标准和通用做法,供参考。
通常对应浏览器重定向到“授权端点(Authorization Endpoint)”的 GET 请求:
请求参数(客户端 -> 授权服务器)
code
。read write profile
。S256
或 plain
(推荐 S256
)。示例:
GET /authorize?
response_type=code
&client_id=abc123
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&scope=read%20profile
&state=xyz987
&code_challenge=XXXXXXXX (若使用 PKCE)
&code_challenge_method=S256 (若使用 PKCE)
响应参数(授权服务器 -> 客户端浏览器重定向)
示例:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?code=abcd1234&state=xyz987
授权码的有效期:通常只有几十秒到几分钟,并且只能使用一次。
对应“令牌端点(Token Endpoint)”的 POST 请求,客户端会使用在上一步拿到的 code
来换取 access_token
(以及可选的 refresh_token
)。
请求参数(客户端 -> 授权服务器)
authorization_code
。通常这些参数会以 application/x-www-form-urlencoded
方式传递在请求体中,或在 HTTP Basic Auth 头里携带 client_id、client_secret。
示例(Body 里带参数):
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=abcd1234
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&client_id=abc123
&client_secret=ssh-secret
&code_verifier=xxxxxx (若使用 PKCE)
响应参数(授权服务器 -> 客户端)
一般返回 JSON,常见字段:
Bearer
。3600
。示例:
{ "access_token": "SlAV32hkKG", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "8xLOxBtZp8", "scope": "read profile" }
在令牌端点(Token Endpoint)再次发起请求,用 refresh_token
换取新的 access_token
(以及可能新的 refresh_token
)。
请求参数(客户端 -> 授权服务器)
refresh_token
。client_secret
(机密客户端)。示例:
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=8xLOxBtZp8
&client_id=abc123
&client_secret=ssh-secret
响应参数(授权服务器 -> 客户端)
通常与“获取 Token”阶段的响应字段类似:
Bearer
。示例:
{ "access_token": "hGFbs732sdf...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "zxcvb0987", "scope": "read profile" }
获取用户信息这一环节在 纯 OAuth 2.0 里并没有强制标准化的“用户信息端点”,但在 OpenID Connect(OIDC)里有明确的 userinfo_endpoint
。
如果只做 OAuth 2.0,你可以自定义一个资源端点让客户端拿着 access_token
去获取用户资料。在 OIDC 的场景下,用户信息是标准化的,常见字段包括 sub
(用户唯一标识)、name
、email
等。
请求方式
https://server.example.com/userinfo
的端点。Authorization: Bearer <access_token>
。示例:
GET /userinfo
Host: server.example.com
Authorization: Bearer SlAV32hkKG
响应内容
sub
、preferred_username
、email
、name
等常见 Claims。示例(OIDC 格式):
{ "sub": "248289761001", "name": "Jane Doe", "preferred_username": "j.doe", "email": "[email protected]", "picture": "http://example.com/janedoe/me.jpg" }
client_id / client_secret
response_type
code
或其他扩展值(隐式模式下是 token
,但已不推荐)。grant_type
authorization_code
、refresh_token
、client_credentials
、password
(后两种并不推荐公开场景使用)。scope
read write profile
)。redirect_uri
code / access_token / refresh_token
expires_in
token_type
Bearer
,表明这是一个不带签名验证(或说仅依赖于传输层安全)的令牌,需要在 HTTPS 下使用。id_token
PKCE 相关字段
S256
;plain
只作为兼容保留。内容类型:
Content-Type: application/x-www-form-urlencoded
。Content-Type: application/json; charset=utf-8
。安全注意:
日志和错误处理:
error
、error_description
、error_uri
字段。OIDC 兼容:
userinfo_endpoint
、id_token
等。在开发 OAuth 2.0 授权服务器的过程中,最重要的是确保:
state
、code_verifier
等)。expires_in
的时间单位)和编码方式(URL 编码、Base64URL 等)都要与 RFC 要求保持一致。上面列出的字段和示例基本涵盖了 OAuth 2.0 标准流程中常见的必需字段和可选字段,希望能帮你在实现自己的 OAuth 2.0 Server 时做参考。祝开发顺利!
Implementing access control
I’m piecing together an approach to use Spring Security for parsing an access token from the HTTP header and verifying the "read" scope. This method might involve custom filters or annotations.
Charting approaches
I’m mapping out a custom annotation or Spring AOP aspect to validate token scopes. Incorporating OAuth2 resource server config with JWTs emerges as a streamlined option.
Piecing together
I'm defining a RequiredScope
annotation and a corresponding aspect to validate token scopes. This involves parsing tokens and integrating with existing login checks for comprehensive security.
Creating a minimal Spring Boot solution
I’m outlining a Java-based approach to implement @RequiredScope
annotation, incorporating a custom method security expression and using @Around
aspect for validation. This approach ensures seamless integration and validation.
Integrating JWT validation
I’m detailing how to parse tokens and check scopes using SecurityContextHolder
. For easier integration, @PreAuthorize
is recommended for standard permissions.
Thought about access token 权限注解,持续 10 秒
下面给出一个示例,展示如何在 Java/Spring 技术栈中,通过 自定义注解 + 切面(AOP) 的方式实现「基于 Access Token + Scope」的权限控制,并且演示如何与现有的登录/鉴权逻辑(如 Session 或其他登录拦截)进行配合。思路如下:
@RequiredScope("xxx")
),由 AOP 切面进行额外的 Scope 检查,只有当 Access Token 所包含的 Scope 满足注解要求时才允许执行方法。当然,如果你已经使用了 Spring Security 的 Method Security(例如
@PreAuthorize("hasAuthority('SCOPE_xxx')")
),也可以直接用它内置的方式来做 Scope 检查。但是本文重点示范“自定义注解 + AOP”的思路,便于定制化逻辑和扩展。
先创建一个注解 @RequiredScope
,可标注在类或方法上:
package com.example.security; import java.lang.annotation.*; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface RequiredScope { /** * 需要具备的scope列表 */ String[] value() default {}; }
@Target({ElementType.METHOD, ElementType.TYPE})
表示可以注解在方法或类上。@Retention(RetentionPolicy.RUNTIME)
表示运行时可见。在使用时,可以写成:
@RequiredScope({"read", "write"}) public void someApiMethod() { ... }
或只写一个:
@RequiredScope("profile") public void userProfileApi() { ... }
为了后续能在切面中获取当前请求对应的 Access Token 及其 Scope,通常需要在“拦截请求”或“过滤器”的阶段先做基础验证。
在 Spring Boot + Spring Security 配置中,一般是这样的流程:
Authorization: Bearer <token>
。scope
字段或 scp
字段中;也可能是一个字符串列表)。SecurityContextHolder
中的 Authentication
或其他共享上下文中,方便后续取用。如果没有使用 Spring Security 的 oauth2ResourceServer()
或更高级的配置,可以自定义一个 OncePerRequestFilter
:
@Component public class BearerTokenFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authHeader = request.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Bearer ")) { String token = authHeader.substring(7); // 假设我们有一个方法 parseToken() 去校验并解析 token // 返回里包含了 scopes、用户信息等 TokenPayload payload = parseToken(token); if (payload != null) { // 将解析结果放到 Spring Security 的上下文 // 这里只示例存放到 Principal 或 Authorities List<GrantedAuthority> authorities = payload.getScopes().stream() .map(scope -> new SimpleGrantedAuthority("SCOPE_" + scope)) .collect(Collectors.toList()); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(payload.getUserId(), null, authorities); // 可以把token本身、scope列表再额外挂到 details 或其他地方 authentication.setDetails(payload); SecurityContextHolder.getContext().setAuthentication(authentication); } } filterChain.doFilter(request, response); } private TokenPayload parseToken(String token) { // 1. 解码/验证签名/JWT解析 // 2. 若成功,返回 TokenPayload(包括 userId, scopes 等) // 3. 若失败,返回 null 或抛异常 return null; // 仅示例 } }
这里的核心是:将 Token 对应的 Scope 转成 GrantedAuthority
并注入到 Spring Security 的 Authentication
里,这样后续的组件就可以从 SecurityContextHolder
获取到用户的 scope/权限信息。
有了上一步的数据上下文后,我们可以用一个 AOP 切面,在进入目标方法时检查是否具备所需 Scope。
package com.example.security; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @Aspect @Component public class RequiredScopeAspect { @Around("@within(requiredScope) || @annotation(requiredScope)") public Object checkScope(ProceedingJoinPoint pjp, RequiredScope requiredScope) throws Throwable { if (requiredScope == null) { // 若类上/方法上没有注解,直接放行 return pjp.proceed(); } // 从注解上获取所需 scope String[] requiredScopes = requiredScope.value(); // 从SecurityContext里拿到当前用户/当前token的Authentication Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth == null || !auth.isAuthenticated()) { throw new RuntimeException("用户未登录或未通过基本认证"); // 或者抛出自定义异常 } // 获取用户所拥有的Scopes,这里假设在Filter里已经存成 SCOPE_xxx Set<String> userScopes = new HashSet<>(); for (GrantedAuthority authority : auth.getAuthorities()) { // 例如 authority.getAuthority() = "SCOPE_read" if (authority.getAuthority().startsWith("SCOPE_")) { userScopes.add(authority.getAuthority().substring("SCOPE_".length())); } } // 判断是否包含所需的每一个 scope for (String rs : requiredScopes) { if (!userScopes.contains(rs)) { throw new RuntimeException("权限不足,需要 scope: " + rs); } } // 校验通过,继续执行目标方法 return pjp.proceed(); } }
说明:
@Around("@within(requiredScope) || @annotation(requiredScope)")
表示:
@RequiredScope
,则类下所有方法都要检查;@RequiredScope
,只检查该方法。GrantedAuthority
(形如 SCOPE_xxx
),在切面里就能读取到。RuntimeException
,实际项目中你可能需要抛出一个 AccessDeniedException
,然后让全局异常处理器捕获后返回相应的 403 响应。有了注解和切面之后,就可以在业务方法上直接标注:
@RestController @RequestMapping("/api") public class UserController { // 需要具备 "read" scope 才能访问 @GetMapping("/user/profile") @RequiredScope("read") public String getUserProfile() { return "This is user profile"; } // 需要具备 "write" scope 才能访问 @PostMapping("/user/update") @RequiredScope("write") public String updateUserProfile() { return "Profile updated"; } }
或者在类级别使用:
@RestController @RequestMapping("/api/orders") @RequiredScope("order") public class OrderController { @GetMapping("/{id}") public String getOrder(@PathVariable Long id) { return "Order detail of " + id; } @PostMapping("/") public String createOrder() { return "Order created"; } }
这样整个 OrderController
下面的接口都需要 scope = order
才可访问。
通常你会同时存在多种“鉴权/拦截”机制,比如:
@PreAuthorize("hasRole('ADMIN')")
。在 Spring Security 框架中,你可以把它们统一到 Security Filter Chain 和 MethodSecurity 中去。关键点在于:
如果你想用 Spring Security 内置的注解来做 Scope 校验,可以直接用
@PreAuthorize("hasAuthority('SCOPE_read')")
这样的表达式,而不必自己写切面。要点是你的 Filter 中要把 Scope 转成GrantedAuthority("SCOPE_xxx")
。
SecurityContext
。@PreAuthorize
等。GrantedAuthority("SCOPE_xxx")
放到 Authentication
里,这样无论是自定义切面还是 Spring Security 内置的 @PreAuthorize
都能用“权限”方式来进行判断。@EnableMethodSecurity
(原 @EnableGlobalMethodSecurity
)和 @PreAuthorize("hasAuthority('SCOPE_write')")
。AccessDeniedException
或 AuthenticationException
,然后通过 ExceptionHandler
或 Security 自带的处理器来返回 HTTP 状态码。以上示例示范了一个 「自定义注解 + 切面 + Scope 检查」 的最小实现思路,并说明了它如何与已有的登录/认证拦截(Filter 或 Spring Security)配合:
@PreAuthorize("hasAuthority('SCOPE_read')")
等功能,但自定义注解更灵活,适合在需要做复杂业务检查时进行扩展。这样就实现了一个基于 Access Token + Scope 的精细化访问控制,并且能够与 Session 或其他登录方式无缝配合。
Crafting the solution
I’m working on a Spring Boot application to intercept and verify access tokens from incoming requests, ensuring security and proper handling of valid or invalid tokens.
Thought about intercepting access token,持续 几秒
下面给出一个在 Spring Boot 环境中「拦截 Access Token」的示例做法,帮助你在请求进来时,能够截获并验证 Token,然后再决定是否放行后续业务逻辑。结合之前提到的「自定义注解 + 切面 + Scope」方案,就可以形成完整的安全校验流程:
Authorization
Header 中的 Access Token。SecurityContextHolder
或者请求上下文中,供后续使用(例如自定义注解切面或 Spring Security 的方法安全 @PreAuthorize
来做更细粒度的权限判断)。下面演示一个 自定义 Filter,在 Spring Boot 中可以让它继承 OncePerRequestFilter
并加上 @Component
或在配置类里注册为 Bean。
package com.example.security; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Component public class AccessTokenFilter extends OncePerRequestFilter { @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 1. 从请求头里拿到Authorization String authHeader = request.getHeader("Authorization"); if (authHeader != null && authHeader.startsWith("Bearer ")) { // 2. 解析出accessToken String accessToken = authHeader.substring(7); try { // 3. 校验token有效性(签名、过期等) // 如果使用JWT,一般要验证签名、exp、issuer等 // 示例:Authentication auth = tokenService.parseAndValidate(accessToken); Authentication auth = validateTokenAndBuildAuthentication(accessToken); // 4. 如果校验成功,把用户信息/权限存到SecurityContext if (auth != null) { SecurityContextHolder.getContext().setAuthentication(auth); } else { // 校验失败的话,可以直接返回401 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; } } catch (Exception e) { // Token 无效或者过期 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; } } else { // 如果没有Bearer Token,你可以选择: // 1) 放行,后面的逻辑可能要求登录才可访问 // 2) 或直接拦截返回401,视业务需求而定 } // 继续过滤器链,后面会进入Controller filterChain.doFilter(request, response); } /** * 假设这是你自己实现的一个方法,用来校验accessToken并构建Authentication */ private Authentication validateTokenAndBuildAuthentication(String accessToken) { // 1. 解码、验证签名,如果是JWT,要解析其中的claims // 2. 如果有效,将token中的用户ID、scope/role 转成Spring Security的 Authentication // 这里仅作示例,返回null代表校验失败 // 正常你会构造 UsernamePasswordAuthenticationToken 或 JWTAuthenticationToken 等 return null; } }
如果你使用了 Spring Boot 的自动配置和 @Component
,一般情况下,这个 AccessTokenFilter
会在 Spring Security Filter Chain 中自动生效。但有时需要你在 Security 配置里显示配置 Filter 的顺序,例如:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private AccessTokenFilter accessTokenFilter; @Override protected void configure(HttpSecurity http) throws Exception { http // 其他配置 .addFilterBefore(accessTokenFilter, UsernamePasswordAuthenticationFilter.class); } }
在新版本 Spring Security 5.7+,
WebSecurityConfigurerAdapter
已被弃用,你可能需要用 SecurityFilterChain Bean 的方式来配置。核心思路类似:把你的自定义 Filter 注册到正确的位置。
AccessTokenFilter
之后,若 Token 有效,就会将 Authentication
放到 SecurityContextHolder
中。SecurityContextHolder.getContext().getAuthentication()
获取当前用户信息和权限 (Scopes/Roles)。@PreAuthorize
来检查“是否具备特定scope或权限”。例如,如果使用 自定义注解 + AOP:
@RestController @RequestMapping("/api") public class SomeController { // 需要'write' scope才能访问 @RequiredScope("write") @PostMapping("/update") public String updateSomething() { // 此时,AccessTokenFilter已经验证了token,并写入了Authentication return "OK"; } }
在切面中,就可以拿到 SecurityContextHolder.getContext().getAuthentication()
,进而判断是否包含 "write"
scope 等。
有时你还想同时支持 Session 登录 和 Token 认证:
JSESSIONID
并且session有效,则 Spring Security 认为已登录,可以访问相应资源;Bearer token
,也可通过 AccessTokenFilter
校验。在 Spring Security 配置里,可以让 Session 机制和 Bearer Token 机制同时存在。关键是确定各个 Filter 的顺序,以及是否允许匿名访问。
Authorization: Bearer <token>
。X-Access-Token
),也可以,但最好跟标准兼容。validateTokenAndBuildAuthentication
方法里验证签名、检查 exp
过期时间、iss
、aud
等字段;同时解析出 sub
(用户ID)和 scope
(权限列表)。401 Unauthorized
。有些场景可能需要返回 JSON,比如 {"error":"invalid_token"}
,你可以在Filter里写 response.getWriter().write(...)
并返回。Authorization
头读取 Token,若合法则放行、若不合法则立即返回 401。SecurityContextHolder
里,这样后续自定义注解 + AOP 或 Spring Security 的 方法级别安全(@PreAuthorize
等)都能正常读取并进行权限判断。这样,你就拥有了一个完整的「拦截 Access Token + Scope 权限注解」的安全框架。
Crafting API paths
OK, let’s think this through: stable and versioned structures work for APIs. Consider /api/
for base, /v1/
for versioning, or /oauth2/
for standards.
Thought about API path conventions,持续 几秒
在对外开放(尤其面向第三方)的 API 设计中,路径通常会遵循一些约定俗成的命名规范,以便清晰区分、方便维护和升级。常见的做法主要有以下几种:
/api
前缀 + 版本号这是最常见的 RESTful API 约定,比如:
/api/v1/...
/api/v2/...
举例:
GET /api/v1/users
POST /api/v1/users
...
日后如果接口发生不兼容的变化,就可以推出 /api/v2/...
并在一定过渡期后淘汰 /api/v1/...
。
有些公司会将外部 API 独立到一个子域名,如 api.example.com
,再在路径中使用 /v1
、/v2
进行版本标识:
https://api.example.com/v1/users
https://api.example.com/v2/users
这样可以在部署和配置层面更灵活,例如负载均衡、缓存、CDN、独立网关等,方便与主站区分。
如果你还需要对外开放 OAuth2.0 授权、令牌等端点,通常会有类似:
POST /oauth/token
GET /oauth/authorize
POST /oauth/token/introspect
POST /oauth/token/revoke
或 /oauth2/token
、/oauth2/authorize
等。
/oauth
,但行业习惯多用 /oauth
或 /oauth2
作为前缀。如果还存在后台管理端点或内部接口,一般会单独放在:
/admin/...
/internal/...
以区分与公开接口的边界,通常也会加更严格的访问控制。
在微服务或网关架构里,你可能会有 API Gateway 将各微服务的路径统一暴露成类似:
/api/user-service/v1/...
/api/order-service/v1/...
或通过 api.example.com/users
、api.example.com/orders
区分。核心思想仍然是:对外统一、对内解耦,并且可以做版本管理和权限控制。
/api/v1/orders
、/api/v1/products
。/api/v1/oauth/...
下,或者直接 /oauth2/...
,只要保证公开文档里说明清楚即可。假设你要对外开放一组用户信息与订单管理的 RESTful API,并提供 OAuth2.0 认证,可能会这样设计:
# OAuth2.0 相关
POST /oauth/token -> 获取Token
GET /oauth/authorize -> 授权端点
POST /oauth/token/revoke -> 撤销Token
# API 主体(版本v1)
GET /api/v1/users -> 获取用户列表
GET /api/v1/users/{id} -> 获取某个用户详情
POST /api/v1/users -> 创建新用户
GET /api/v1/orders -> 获取订单列表
GET /api/v1/orders/{id} -> 获取订单详情
POST /api/v1/orders -> 创建新订单
如果将来接口大改,就新增 /api/v2/...
,保持对旧版的兼容一段时间。
/api/...
为前缀,加上版本号(如 v1
、v2
)是常见最佳实践。api.example.com/v1/
的形式。/oauth/...
或 /oauth2/...
。/admin/...
、/internal/...
。