Auth0 API + Spring:如何从成功的 Auth0 API 响应中验证用户身份
Auth0 API + Spring: How to verify user identity from successful Auth0 API response
问题
我正在尝试创建一个应用程序,该应用程序在前端使用 Auth0 SPA + React 来对用户进行身份验证,而无需处理密码。然后,我想保护我使用 Auth 服务器创建的任何端点,我需要使用 Spring Framework[=58= 创建].
澄清一下,流程是
Frontend ->
Auth through Auth0 ->
Redirect to users dashboard on frontend ->
Make HTTP request to endpoint sending JWT returned from Auth0 ->
Endpoint makes request to my Auth Server sending JWT returned from Auth0 ->
Auth server either either returns 401 or user object based on JWT ->
Endpoint grabs data specific to that user from DB ->
Returns data to frontend
我已经使用 Auth0 提供的 快速入门指南 使我的前端正常工作,但我有一个弄清楚如何让我的 Auth 服务 验证用户有很多麻烦。
我相信我已经得出结论,我需要在 Auth0 上创建一个“API”并且获取一个 access token 并使用它来验证 JWT,在本例中它只是 access token 而不是我的前端包含的 JWT。我也让这部分工作,但似乎没有办法知道用户是谁。测试此“API”时,发送有效请求后我返回
{
"iss": "https://${username}.auth0.com/",
"sub": "${alphanumericCharacters}@clients",
"aud": "${ApiIdentifier}",
"iat": ${issuedAt},
"exp": ${expiresAt},
"azp": "${alphanumericCharacters}",
"gty": "client-credentials"
}
虽然很高兴知道我走在正确的轨道上,但我似乎无法弄清楚如何处理此响应来找到用户。
预计
我希望在从我的 Auth Service[=18 验证 access_token 后能够识别特定用户=]
代码
我没有太多代码可以展示,但我会提供我的 Auth 服务
SecurityConfiguration.java
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${auth0.audience}")
private String audience;
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.mvcMatchers("/api/validate")
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport)
JwtDecoders.fromOidcIssuerLocation(issuer);
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
jwtDecoder.setJwtValidator(withAudience);
return jwtDecoder;
}
}
AudienceValidator.java
public class AudienceValidator implements OAuth2TokenValidator<Jwt> {
private final String audience;
public AudienceValidator(String audience) {
this.audience = audience;
}
public OAuth2TokenValidatorResult validate(Jwt jwt) {
OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);
if (jwt.getAudience().contains(audience)) {
return OAuth2TokenValidatorResult.success();
}
return OAuth2TokenValidatorResult.failure(error);
}
}
ValidateController.java
@RestController
@RequestMapping("/api/validate")
public class ValidateController {
@GetMapping
public boolean validate() {
return true; // only returns if successfully authed
}
}
阅读文档后,我找到了解决方案。
事实证明,我不需要在 Auth0 上创建“API”,而是需要使用来自 Auth0 的 Applications 端点。 Auth0 根据您的帐户提供许多端点,您可以从任何应用程序(CLI、服务器、客户端等)中充分利用这些端点,只要您可以:
- 发出 HTTP 请求
- 提供凭据
所以获取用户信息的方式是explained here。
数据流
使用我的项目auth/data flow 差不多:
使用@auth0/auth0-spa-js on the frontend, you can grab a users access token after a successful auth by using the getTokenSilently() method.
向您的 Rest 服务发送 HTTP 请求
Rest 服务 将该令牌发送到您的 Auth 服务
Auth Service 发送 GET 请求到 https://myAuth0Username.auth0.com/userinfo
Authorization: Bearer ${access_token}
header。 Example
如果从 Auth0
成功验证
- Returns 您的用户信息,例如 "name"、"email" 等
其他
- Returns 403 禁止 HTTP 状态
Auth Service 然后 returns user object to 休息服务
Rest Service 然后为该端点执行必要的逻辑(数据库查询、另一个 HTTP 请求等)
用于验证令牌和 return 用户的示例 Auth 服务端点
ValidateController.java
package x.SpringTodo_Auth.Controllers;
import x.SpringTodo_Auth.Models.User;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/api/validate")
public class ValidateController {
@GetMapping
public Object validate() {
// Create and set the "Authorization" header before sending HTTP request
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + access_token);
HttpEntity<String> entity = new HttpEntity<>("headers", headers);
// Use the "RestTemplate" API provided by Spring to make the HTTP request
RestTemplate restTemplate = new RestTemplate();
Object user = restTemplate.exchange("https://myAuth0Username.auth0.com/userinfo", HttpMethod.POST, entity, User.class);
return user;
}
}
User.java(这是作为最后一个参数传递给restTemplate.exchange(...)
方法的class
package x.SpringTodo_Auth.Models;
public class User {
private String sub;
private String given_name;
private String family_name;
private String nickname;
private String name;
private String picture;
private String locale;
private String updated_at;
private String email;
private boolean email_verified;
// Getters/setters (or you can use Lombok)
}
问题
我正在尝试创建一个应用程序,该应用程序在前端使用 Auth0 SPA + React 来对用户进行身份验证,而无需处理密码。然后,我想保护我使用 Auth 服务器创建的任何端点,我需要使用 Spring Framework[=58= 创建].
澄清一下,流程是
Frontend ->
Auth through Auth0 ->
Redirect to users dashboard on frontend ->
Make HTTP request to endpoint sending JWT returned from Auth0 ->
Endpoint makes request to my Auth Server sending JWT returned from Auth0 ->
Auth server either either returns 401 or user object based on JWT ->
Endpoint grabs data specific to that user from DB ->
Returns data to frontend
我已经使用 Auth0 提供的 快速入门指南 使我的前端正常工作,但我有一个弄清楚如何让我的 Auth 服务 验证用户有很多麻烦。
我相信我已经得出结论,我需要在 Auth0 上创建一个“API”并且获取一个 access token 并使用它来验证 JWT,在本例中它只是 access token 而不是我的前端包含的 JWT。我也让这部分工作,但似乎没有办法知道用户是谁。测试此“API”时,发送有效请求后我返回
{
"iss": "https://${username}.auth0.com/",
"sub": "${alphanumericCharacters}@clients",
"aud": "${ApiIdentifier}",
"iat": ${issuedAt},
"exp": ${expiresAt},
"azp": "${alphanumericCharacters}",
"gty": "client-credentials"
}
虽然很高兴知道我走在正确的轨道上,但我似乎无法弄清楚如何处理此响应来找到用户。
预计
我希望在从我的 Auth Service[=18 验证 access_token 后能够识别特定用户=]
代码
我没有太多代码可以展示,但我会提供我的 Auth 服务
SecurityConfiguration.java
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Value("${auth0.audience}")
private String audience;
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
private String issuer;
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.mvcMatchers("/api/validate")
.authenticated()
.and()
.oauth2ResourceServer()
.jwt();
}
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport)
JwtDecoders.fromOidcIssuerLocation(issuer);
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(audience);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuer);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
jwtDecoder.setJwtValidator(withAudience);
return jwtDecoder;
}
}
AudienceValidator.java
public class AudienceValidator implements OAuth2TokenValidator<Jwt> {
private final String audience;
public AudienceValidator(String audience) {
this.audience = audience;
}
public OAuth2TokenValidatorResult validate(Jwt jwt) {
OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null);
if (jwt.getAudience().contains(audience)) {
return OAuth2TokenValidatorResult.success();
}
return OAuth2TokenValidatorResult.failure(error);
}
}
ValidateController.java
@RestController
@RequestMapping("/api/validate")
public class ValidateController {
@GetMapping
public boolean validate() {
return true; // only returns if successfully authed
}
}
阅读文档后,我找到了解决方案。
事实证明,我不需要在 Auth0 上创建“API”,而是需要使用来自 Auth0 的 Applications 端点。 Auth0 根据您的帐户提供许多端点,您可以从任何应用程序(CLI、服务器、客户端等)中充分利用这些端点,只要您可以:
- 发出 HTTP 请求
- 提供凭据
所以获取用户信息的方式是explained here。
数据流
使用我的项目auth/data flow 差不多:
使用@auth0/auth0-spa-js on the frontend, you can grab a users access token after a successful auth by using the getTokenSilently() method.
向您的 Rest 服务发送 HTTP 请求
Rest 服务 将该令牌发送到您的 Auth 服务
Auth Service 发送 GET 请求到
https://myAuth0Username.auth0.com/userinfo
Authorization: Bearer ${access_token}
header。 Example如果从 Auth0
成功验证- Returns 您的用户信息,例如 "name"、"email" 等
其他
- Returns 403 禁止 HTTP 状态
Auth Service 然后 returns user object to 休息服务
Rest Service 然后为该端点执行必要的逻辑(数据库查询、另一个 HTTP 请求等)
用于验证令牌和 return 用户的示例 Auth 服务端点
ValidateController.java
package x.SpringTodo_Auth.Controllers;
import x.SpringTodo_Auth.Models.User;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/api/validate")
public class ValidateController {
@GetMapping
public Object validate() {
// Create and set the "Authorization" header before sending HTTP request
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + access_token);
HttpEntity<String> entity = new HttpEntity<>("headers", headers);
// Use the "RestTemplate" API provided by Spring to make the HTTP request
RestTemplate restTemplate = new RestTemplate();
Object user = restTemplate.exchange("https://myAuth0Username.auth0.com/userinfo", HttpMethod.POST, entity, User.class);
return user;
}
}
User.java(这是作为最后一个参数传递给restTemplate.exchange(...)
方法的class
package x.SpringTodo_Auth.Models;
public class User {
private String sub;
private String given_name;
private String family_name;
private String nickname;
private String name;
private String picture;
private String locale;
private String updated_at;
private String email;
private boolean email_verified;
// Getters/setters (or you can use Lombok)
}