auth0 jwt аутентификация Ошибка разбора токена: токен использовался до выдачи - PullRequest
0 голосов
/ 02 марта 2020

Я успешно настроил аутентификацию с Auth0, однако, когда Auth0 перенаправляет обратно на мой обратный вызов, я не могу получить доступ к ajax конечным точкам.

Однако, если я обновлю sh страницу (без повторной аутентификации), я теперь могу. Я вижу в localStorage, что access_token был установлен. Поэтому кажется странным, что при обновлении sh токен установлен, но в первый раз его нет.

Я подозреваю, что загружаю компоненты до установки localStorage, а это означает, что запрос к API завершается неудачно. Однако я не уверен в исправлении.

Я получаю ошибку Error parsing token: Token used before issued и 401 при запросе к API

Мой код ниже:

Im используя библиотеки

"github.com/auth0/go-jwt-middleware"
"github.com/dgrijalva/jwt-go"

Я инициализирую проверку токена здесь:

func (h *Page) Init() error {
    h.JWTMiddleware = jwtmiddleware.New(jwtmiddleware.Options{
        ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
            aud := os.Getenv("AUTH0_API_AUDIENCE")
            checkAudience := token.Claims.(jwt.MapClaims).VerifyAudience(aud, false)
            if !checkAudience {
                return token, errors.New("Invalid audience.")
            }
            // verify iss claim
            iss := os.Getenv("AUTH0_DOMAIN")
            fmt.Println("iss == ", iss)
            checkIss := token.Claims.(jwt.MapClaims).VerifyIssuer(iss, false)
            if !checkIss {
                return token, errors.New("Invalid issuer.")
            }

            cert, err := getPemCert(token)
            if err != nil {
                fmt.Println("could not get cert: %+v", err)
                return cert, err
            }

            result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert))
            return result, nil
        },
        SigningMethod: jwt.SigningMethodRS256,
    })

    return nil
}

Я настраиваю pem и мое промежуточное ПО здесь

func (h *Page) authMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        // Get the client secret key
        err := h.JWTMiddleware.CheckJWT(c.Writer, c.Request)
        if err != nil {
            // Token not found
            fmt.Println("error checking jwt ", err)           <<<---- FAILS HERE!
            c.Abort()
            c.Writer.WriteHeader(http.StatusUnauthorized)
            c.Writer.Write([]byte("Unauthorized"))
            return
        }
    }
}

func getPemCert(token *jwt.Token) (string, error) {
    cert := ""
    resp, err := http.Get(os.Getenv("AUTH0_DOMAIN") + ".well-known/jwks.json")
    if err != nil {
        return cert, err
    }
    defer resp.Body.Close()

    var jwks = Jwks{}
    err = json.NewDecoder(resp.Body).Decode(&jwks)

    if err != nil {
        return cert, err
    }

    x5c := jwks.Keys[0].X5c
    for k, v := range x5c {
        if token.Header["kid"] == jwks.Keys[k].Kid {
            cert = "-----BEGIN CERTIFICATE-----\n" + v + "\n-----END CERTIFICATE-----"
        }
    }
    if cert == "" {
        return cert, errors.New("unable to find appropriate key")
    }

    return cert, nil
}

и мой интерфейс реакции здесь


const AUTH0_CLIENT_ID = "xxx7vOQeStuKmaNfwxoWX"//'{{ $variables := index .Globals "jokish.so"}}{{index $variables "auth0-key"}}';
const AUTH0_DOMAIN = "xxx.eu.auth0.com"//'{{ $variables := index .Globals "jokish.so"}}{{index $variables "domain"}}';
const AUTH0_CALLBACK_URL = "http://localhost:9000/jokes/callback"//'{{ $variables := index .Globals "jokish.so"}}{{index $variables "callback"}}';
const AUTH0_API_AUDIENCE = "https://xxx.eu.auth0.com/api/v2/"//'{{ $variables := index .Globals "jokish.so"}}{{index $variables "audience"}}';

class App extends React.Component {
    parseHash() {
        this.auth0 = new auth0.WebAuth({
            domain: AUTH0_DOMAIN,
            clientID: AUTH0_CLIENT_ID
        });
        this.auth0.parseHash(window.location.hash, (err, authResult) => {
            if (err) {
                return console.log(err);
            }
            if (
                authResult !== null &&
                authResult.accessToken !== null &&
                authResult.idToken !== null
            ) {
                localStorage.setItem("access_token", authResult.accessToken);
                localStorage.setItem("id_token", authResult.idToken);
                localStorage.setItem(
                    "profile",
                    JSON.stringify(authResult.idTokenPayload)
                );
                window.location = window.location.href.substr(
                    0,
                    window.location.href.indexOf("#")
                );
            }
        });
    }

    setup() {
        $.ajaxSetup({
            beforeSend: (r) => {
                console.log("setting ajax up with token ", localStorage.getItem("access_token"))
                if (localStorage.getItem("access_token")) {
                    r.setRequestHeader(
                        "Authorization",
                        "Bearer " + localStorage.getItem("access_token")
                    );
                }
            }
        });
    }

    setState() {
        let idToken = localStorage.getItem("id_token");
        if (idToken) {
            this.loggedIn = true;
        } else {
            this.loggedIn = false;
        }
    }

    componentWillMount() {
        this.setup();
        this.parseHash();
        this.setState();
    }

    render() {
        if (this.loggedIn) {
            return <LoggedIn />;
        }
        return <Home />;
    }
}

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.authenticate = this.authenticate.bind(this);
    }
    authenticate() {
        this.WebAuth = new auth0.WebAuth({
            domain: AUTH0_DOMAIN,
            clientID: AUTH0_CLIENT_ID,
            scope: "openid profile",
            audience: AUTH0_API_AUDIENCE,
            responseType: "token id_token",
            redirectUri: AUTH0_CALLBACK_URL
        });
        this.WebAuth.authorize();
    }

    render() {
        return (
            <div className="container">
                <div className="row">
                    <div className="col-xs-8 col-xs-offset-2 jumbotron text-center">
                        <h1>Jokeish</h1>
                        <p>A load of Dad jokes XD</p>
                        <p>Sign in to get access </p>
                        <a
                            onClick={this.authenticate}
                            className="btn btn-primary btn-lg btn-login btn-block"
                        >
                            Sign In
                        </a>
                    </div>
                </div>
            </div>
        );
    }
}

class LoggedIn extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            jokes: []
        };

        this.serverRequest = this.serverRequest.bind(this);
        this.logout = this.logout.bind(this);
    }

    logout() {
        localStorage.removeItem("id_token");
        localStorage.removeItem("access_token");
        localStorage.removeItem("profile");
        location.reload();
    }

    serverRequest() {
        $.get("http://localhost:9000/jokes/api/jokes", res => {
            this.setState({
                jokes: res
            });
        });
    }

    componentDidMount() {
        this.serverRequest();
    }

    render() {
        return (
            <div className="container">
                <br />
                <span className="pull-right">
          <a onClick={this.logout}>Log out</a>
        </span>
                <h2>Jokeish</h2>
                <p>Let's feed you with some funny Jokes!!!</p>
                <div className="row">
                    <div className="container">
                        {this.state.jokes.map(function(joke, i) {
                            return <Joke key={i} joke={joke} />;
                        })}
                    </div>
                </div>
            </div>
        );
    }
}

class Joke extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            liked: "",
            jokes: []
        };
        this.like = this.like.bind(this);
        this.serverRequest = this.serverRequest.bind(this);
    }

    like() {
        let joke = this.props.joke;
        this.serverRequest(joke);
    }
    serverRequest(joke) {
        $.post(
            "http://localhost:9000/jokes/api/jokes/like/" + joke.id,
            { like: 1 },
            res => {
                console.log("res... ", res);
                this.setState({ liked: "Liked!", jokes: res });
                this.props.jokes = res;
            }
        );
    }

    render() {
        return (
            <div className="col-xs-4">
                <div className="panel panel-default">
                    <div className="panel-heading">
                        #{this.props.joke.id}{" "}
                        <span className="pull-right">{this.state.liked}</span>
                    </div>
                    <div className="panel-body joke-hld">{this.props.joke.joke}</div>
                    <div className="panel-footer">
                        {this.props.joke.likes} Likes &nbsp;
                        <a onClick={this.like} className="btn btn-default">
                            <span className="glyphicon glyphicon-thumbs-up" />
                        </a>
                    </div>
                </div>
            </div>
        );
    }
}
ReactDOM.render(<App />, document.getElementById("app"));

...