Skip to content

Commit 3140c3e

Browse files
committed
✨(@koex/passport): design a strategy for callback return error
- callback error should not throw, let it be handled by common error middleware, should design a new method for it - will face two situations - internal code logic error or strategy is not defined (passport.ts line 166 - 172) - remote provider error when exchange token by code or exchange user by token (passport.ts line 174 - 178)
1 parent b9989d5 commit 3140c3e

2 files changed

Lines changed: 44 additions & 25 deletions

File tree

packages/passport/src/passport.ts

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ export interface InitializeOptions {
4141
onUnauthorized(ctx: Context, acceptJSON: boolean): Promise<void>;
4242
}
4343

44+
export interface CallbackOptions {
45+
onFail(error: Error, ctx: Context, next: any): Promise<void>;
46+
}
47+
4448
export interface LoginOptions {
4549
render?(ctx: Context): Promise<void>;
4650
redirect?: string;
@@ -59,7 +63,7 @@ export interface IPassport {
5963
use(name: string, strategy: Strategy): void;
6064
initialize(options: InitializeOptions): Middleware<Context>;
6165
authenticate(): Middleware<Context>;
62-
callback(): Middleware<Context>;
66+
callback(options: CallbackOptions): Middleware<Context>;
6367
login(options?: LoginOptions): Middleware<Context>;
6468
logout(options?: LogoutOptions): Middleware<Context>;
6569
}
@@ -153,29 +157,33 @@ export class Passport implements IPassport {
153157
};
154158
}
155159

156-
public callback(): Middleware<Context> {
160+
public callback(options: CallbackOptions): Middleware<Context> {
157161
return async (ctx, next) => {
158-
const strategyName = ctx.params.strategy; // @TODO
159-
const strategy = this.strategies[strategyName];
160-
161-
if (!strategyName) {
162-
ctx.throw(500, `No Passport Strategy Name Provided`);
163-
}
164-
165-
if (!strategy) {
166-
ctx.throw(500, `No Passport Strategy provided named ${strategyName}`);
162+
try {
163+
const strategyName = ctx.params.strategy; // @TODO
164+
const strategy = this.strategies[strategyName];
165+
166+
if (!strategyName) {
167+
ctx.throw(500, `No Passport Strategy Name Provided`, { strategy: strategyName, reasonBy: 'self' });
168+
}
169+
170+
if (!strategy) {
171+
ctx.throw(500, `No Passport Strategy provided named ${strategyName}`, { strategy: strategyName, reasonBy: 'self' });
172+
}
173+
174+
const profile = await strategy.callback(ctx);
175+
176+
this.session.set(strategyName, profile.id);
177+
178+
const user = await strategy.getUserByStrategyProfile(ctx, strategyName, profile, Stage.authorize);
179+
180+
// readonly, use it instead of ctx.user = user
181+
defineReadonlyProperties(ctx, { user });
182+
183+
return await next();
184+
} catch (error) {
185+
return await options.onFail(error, ctx, next);
167186
}
168-
169-
const profile = await strategy.callback(ctx);
170-
171-
this.session.set(strategyName, profile.id);
172-
173-
const user = await strategy.getUserByStrategyProfile(ctx, strategyName, profile, Stage.authorize);
174-
175-
// readonly, use it instead of ctx.user = user
176-
defineReadonlyProperties(ctx, { user });
177-
178-
await next();
179187
};
180188
}
181189

packages/passport/src/use.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,20 @@ export function usePassport(app: App, options: IUsePassport) {
159159
// @S1 authenticate flow
160160
app.get(authenticatePath, passport.authenticate());
161161
// @S2 callback flow
162-
app.get(callbackPath, passport.callback(), async (ctx: Context) => {
163-
await onAuthorized(ctx, _options);
164-
});
162+
app.get(
163+
callbackPath,
164+
passport.callback({
165+
async onFail(error: any, ctx) {
166+
// @TODO log erro
167+
console.error('oauth callback error: ', error);
168+
// @TODO send error to login page, should only once, login page should remove error
169+
return ctx.redirect(`${loginPath}?error=${error.strategy}授权失败(来源: ${error.reasonBy})`);
170+
},
171+
}),
172+
async (ctx: Context) => {
173+
await onAuthorized(ctx, _options);
174+
},
175+
);
165176

166177
// passport login url, you can act redirect or render page
167178
app.get(loginPath, passport.login({

0 commit comments

Comments
 (0)