【问题标题】:Auth0 API + Spring: How to verify user identity from successful Auth0 API responseAuth0 API + Spring:如何从成功的 Auth0 API 响应中验证用户身份
【发布时间】:2020-01-22 12:20:42
【问题描述】:

问题

我正在尝试创建一个应用程序,它在前端使用 Auth0 SPA + React 来验证用户,而无需处理密码。然后,我想保护我使用 Auth 服务器创建的所有端点,我需要使用 Spring Framework 创建。

澄清一下,流程是

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 Service 来验证用户。

我相信我已经得出结论,我需要在 Auth0 上创建一个“API”并获取一个访问令牌和使用它来验证 JWT,在这种情况下它只是 访问令牌 而不是我的前端包含的 JWT。我也让这部分工作,但似乎没有办法知道用户是谁。测试此“API”时,发送有效请求后,我被退回

{
  "iss": "https://${username}.auth0.com/",
  "sub": "${alphanumericCharacters}@clients",
  "aud": "${ApiIdentifier}",
  "iat": ${issuedAt},
  "exp": ${expiresAt},
  "azp": "${alphanumericCharacters}",
  "gty": "client-credentials"
}

虽然很高兴知道我在正确的轨道上,但我似乎无法弄清楚如何处理此响应以找到用户。

预期

我希望在验证 Auth Service

中的 access_token 后能够识别特定用户

代码

我没有太多要展示的代码,但我会提供我的 Auth Service

中所能提供的

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
    }

}

【问题讨论】:

    标签: java spring spring-boot jwt auth0


    【解决方案1】:

    通读文档后,我找到了解决方案。

    事实证明,我不需要在 Auth0 上创建“API”,而是需要使用我的 Applications 端点( s) 来自 Auth0Auth0 会根据您的帐户提供许多端点,您可以从任何应用程序(CLI、服务器、客户端等)中利用这些端点,只要您可以:

    • 发出 HTTP 请求
    • 提供凭据

    所以获取用户信息的方法是explained here

    数据流

    使用我的项目身份验证/数据流就差不多了:

    • 在前端使用@auth0/auth0-spa-js,您可以在通过getTokenSilently() method 成功验证后获取用户访问令牌

    • 向您的 Rest Service

    • 发送 HTTP 请求
    • Rest Service 将该令牌发送到您的 Auth Service

    • Auth Servicehttps://myAuth0Username.auth0.com/userinfo 发送带有Authorization: Bearer ${access_token} 标头的GET 请求。 Example

    • 如果从 Auth0

      成功验证
      • 返回您的用户信息,例如“姓名”、“电子邮件”等。
    • 其他

      • 返回 403 禁止 HTTP 状态
    • Auth Service 然后将 user object 返回到 Rest Service

    • Rest Service 然后为该端点执行必要的逻辑(数据库查询、另一个 HTTP 请求等)

    验证令牌并返回用户的示例验证服务端点

    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(...)方法的类

    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)
    }
    

    【讨论】:

      猜你喜欢
      • 2017-04-27
      • 2018-09-22
      • 2018-09-08
      • 2015-04-10
      • 2017-01-14
      • 2019-08-11
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多