【问题标题】:Integrate Auth0 as middleware in Express.js routing-controllers authorizationChecker在 Express.js 路由控制器授权检查器中集成 Auth0 作为中间件
【发布时间】:2020-12-15 02:41:46
【问题描述】:

我在将Auth0's Node (Express) API quickstart 转换为中间件变体时遇到了困难。特别是使用 TypeStack 的 routing-controllers 库并希望使用他们的 @Authorized decorator 集成 Auth0。

app.ts 中:

const app = createExpressServer({

    authorizationChecker: async (action: Action, roles: string[]) => {
        const token = action.request.headers['authorization'];

        // QUESTION: How to validate the bearer token here so it returns true/false
        // + also respect the role ('super-duper-trooper')?

        return true/false;   // <----- this
        
    },

    controllers: [StatusController]
});

status-controller.ts 我用@Authorized + 一个角色来装饰一个操作:

@Controller()
export class StatusController {

    @Get('/status')
    getAll() {
       return 'OK, anonymously accessible';
    }

    @Authorized('super-duper-trooper')   // <----- that
    @Get('/status/:id')
    getOne(@Param('id') id: string) {
       return 'NOT OK';
    }
}

我的问题:如何配置 authorizationChecker 函数,以便它既验证令牌又尊重角色(上例中的“super-duper-trooper”)?

注意我尝试将其添加为常规 Express.js 中间件 (app.use(MyMiddleware)),但这已被 authorizationChecker 函数取代。

【问题讨论】:

    标签: typescript express auth0 routing-controllers


    【解决方案1】:

    我已经设法让authorizationChecker 为 Express.js 中的路由控制器工作。

    我通过合并 jsonwebtokenjwks-rsa 库来做到这一点。

    请参阅以下验证给定 JWT 的身份验证函数:

    import jwt from 'jsonwebtoken';
    import jwksRsa from 'jwks-rsa';
    
    export async function AuthMiddleware(token: string, roles: string[]): Promise<boolean> {
        if (!token) return false;
    
        // Extracts the bearer token from the request headers
        const bearerToken = token.split(' ')[1];
    
        // Set up a JWKS client that retrieves the public key from Auth0, this public key will be used to challenge the
        // bearer token against.
        const client = jwksRsa({
            jwksUri: 'https://your_jwks_uri.com/jwks.json' // For example, using Auth0 you can find this in Auth0 Applications -> Advanced Settings -> Endpoints. This should look something like this: https://yourtenant.eu.auth0.com/.well-known/jwks.json
        });
        const getPublicKey = (header: any, callback: any) => {
            client.getSigningKey(header.kid, (err, key) => {
                const signingKey = key.getPublicKey();
                callback(null, signingKey);
            });
        }
    
        // As jwt.verify cannot be awaited, we construct a promise that we will resolve once the JWT verification has
        // finished. This way, we can simulate awaiting of the JWT verification.
        let jwtVerifyPromiseResolver: (tokenValid: boolean) => void;
        const jwtVerifyPromise = new Promise<boolean>(resolve => {
            jwtVerifyPromiseResolver = resolve;
        });
    
        const tokenNamespace = 'your_namespace'; // The namespace you have added to the roles in your auth token in an Auth0 rule
    
        jwt.verify(bearerToken, getPublicKey, {}, (err, decodedJwt: any) => {
            let jwtValid: boolean = false;
    
            if (err)
                jwtValid = false;
            else {
                // When the requested endpoint requires roles, check if the decoded JWT contains those roles
                if (roles && roles.length > 0) {
                    const userRoles = decodedJwt[`${tokenNamespace}roles`];
    
                    if (userRoles)
                        // Token is valid if all roles for request are present in the user's roles
                        jwtValid = roles.every((role) => userRoles.includes(role));
                    else
                        // Token does not contain roles, mark token as invalid
                        jwtValid = false;
                }
    
                jwtValid = true;
            }
    
            jwtVerifyPromiseResolver(
                jwtValid
            );
        });
    
        return jwtVerifyPromise;
    }
    

    然后可以在authorizationToken 函数中使用此函数,如下所示:

    const app = createExpressServer({
        authorizationChecker: async (action: Action, roles: string[]) => {
            const authorizationToken = action.request.headers['authorization'];
    
            // Wait for JWT verification to complete, returning whether the token is valid or not
            return await AuthMiddleware(authorizationToken, roles);
        },
    
        controllers: [StatusController]
    });
    

    配置完成后,您可以使用@Authorize()@Authorize('role') 来装饰控制器中的操作,就像您已经在做的那样。这将在对操作的每个请求之前触发authorizationChecker

    注意:从端点检索公钥的整个getPublicKey 部分也可以通过在代码中或在某个设置中使用公钥来替换。这样,您也不需要手动创建 Promise 来等待 JWT 验证。不过,我认为按需检索公钥是更优雅的解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-14
      • 2017-01-13
      • 2012-08-23
      • 2017-12-18
      • 2018-03-09
      • 1970-01-01
      相关资源
      最近更新 更多