mirror of
https://github.com/wassname/talk.git
synced 2026-07-29 11:28:24 +08:00
feat: added google support
This commit is contained in:
@@ -7,6 +7,7 @@ import passport, { Authenticator } from "passport";
|
||||
|
||||
import { Config } from "talk-common/config";
|
||||
import FacebookStrategy from "talk-server/app/middleware/passport/strategies/facebook";
|
||||
import GoogleStrategy from "talk-server/app/middleware/passport/strategies/google";
|
||||
import { JWTStrategy } from "talk-server/app/middleware/passport/strategies/jwt";
|
||||
import { createLocalStrategy } from "talk-server/app/middleware/passport/strategies/local";
|
||||
import OIDCStrategy from "talk-server/app/middleware/passport/strategies/oidc";
|
||||
@@ -54,6 +55,9 @@ export function createPassport(
|
||||
// Use the FacebookStrategy.
|
||||
auth.use(new FacebookStrategy(options));
|
||||
|
||||
// Use the GoogleStrategy.
|
||||
auth.use(new GoogleStrategy(options));
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,8 @@ export default class FacebookStrategy extends OAuth2Strategy<
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: maybe update user details?
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import { Db } from "mongodb";
|
||||
import { Profile, Strategy } from "passport-google-oauth2";
|
||||
|
||||
import { Config } from "talk-common/config";
|
||||
import OAuth2Strategy from "talk-server/app/middleware/passport/strategies/oauth2";
|
||||
import { reconstructTenantURL } from "talk-server/app/url";
|
||||
import {
|
||||
GQLAuthIntegrations,
|
||||
GQLGoogleAuthIntegration,
|
||||
GQLUSER_ROLE,
|
||||
} from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { Tenant } from "talk-server/models/tenant";
|
||||
import {
|
||||
GoogleProfile,
|
||||
retrieveUserWithProfile,
|
||||
} from "talk-server/models/user";
|
||||
import TenantCache from "talk-server/services/tenant/cache";
|
||||
import { upsert } from "talk-server/services/users";
|
||||
|
||||
export interface GoogleStrategyOptions {
|
||||
config: Config;
|
||||
mongo: Db;
|
||||
tenantCache: TenantCache;
|
||||
}
|
||||
|
||||
export interface GoogleStrategyOptions {
|
||||
config: Config;
|
||||
mongo: Db;
|
||||
tenantCache: TenantCache;
|
||||
}
|
||||
|
||||
export default class GoogleStrategy extends OAuth2Strategy<
|
||||
GQLGoogleAuthIntegration,
|
||||
Strategy
|
||||
> {
|
||||
public name = "google";
|
||||
|
||||
constructor(options: GoogleStrategyOptions) {
|
||||
super({
|
||||
...options,
|
||||
scope: ["profile"],
|
||||
});
|
||||
}
|
||||
|
||||
protected getIntegration = (integrations: GQLAuthIntegrations) =>
|
||||
integrations.google;
|
||||
|
||||
protected async findOrCreateUser(
|
||||
tenant: Tenant,
|
||||
integration: Required<GQLGoogleAuthIntegration>,
|
||||
{ id, photos, emails, displayName }: Profile
|
||||
) {
|
||||
// Create the user profile that will be used to lookup the User.
|
||||
const profile: GoogleProfile = {
|
||||
type: "google",
|
||||
id,
|
||||
};
|
||||
|
||||
let user = await retrieveUserWithProfile(this.mongo, tenant.id, profile);
|
||||
if (!user) {
|
||||
if (!integration.allowRegistration) {
|
||||
// Registration is disabled, so we can't create the user user here.
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: implement rules.
|
||||
|
||||
// Try to get the avatar.
|
||||
let avatar: string | undefined;
|
||||
if (photos && photos.length > 0) {
|
||||
avatar = photos[0].value;
|
||||
}
|
||||
|
||||
// Try to get the email address.
|
||||
let email: string | undefined;
|
||||
let emailVerified: boolean | undefined;
|
||||
if (emails && emails.length > 0) {
|
||||
email = emails[0].value;
|
||||
emailVerified = false;
|
||||
}
|
||||
|
||||
user = await upsert(this.mongo, tenant, {
|
||||
username: null,
|
||||
displayName,
|
||||
role: GQLUSER_ROLE.COMMENTER,
|
||||
email,
|
||||
email_verified: emailVerified,
|
||||
avatar,
|
||||
profiles: [profile],
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: maybe update user details?
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
protected createStrategy(
|
||||
tenant: Tenant,
|
||||
integration: Required<GQLGoogleAuthIntegration>
|
||||
) {
|
||||
return new Strategy(
|
||||
{
|
||||
clientID: integration.clientID,
|
||||
clientSecret: integration.clientSecret,
|
||||
callbackURL: reconstructTenantURL(
|
||||
this.config,
|
||||
tenant,
|
||||
"/api/tenant/auth/google/callback"
|
||||
),
|
||||
passReqToCallback: true,
|
||||
},
|
||||
this.verifyCallback
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ export interface OAuth2StrategyOptions {
|
||||
config: Config;
|
||||
mongo: Db;
|
||||
tenantCache: TenantCache;
|
||||
scope?: string[];
|
||||
}
|
||||
|
||||
export default abstract class OAuth2Strategy<
|
||||
@@ -30,13 +31,15 @@ export default abstract class OAuth2Strategy<
|
||||
protected config: Config;
|
||||
protected mongo: Db;
|
||||
protected cache: TenantCacheAdapter<U>;
|
||||
private scope?: string[];
|
||||
|
||||
constructor({ config, mongo, tenantCache }: OAuth2StrategyOptions) {
|
||||
constructor({ config, mongo, tenantCache, scope }: OAuth2StrategyOptions) {
|
||||
super();
|
||||
|
||||
this.config = config;
|
||||
this.mongo = mongo;
|
||||
this.cache = new TenantCacheAdapter(tenantCache);
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
protected abstract getIntegration(integrations: GQLAuthIntegrations): T;
|
||||
@@ -114,7 +117,10 @@ export default abstract class OAuth2Strategy<
|
||||
strategy.redirect = this.redirect.bind(this);
|
||||
strategy.success = this.success.bind(this);
|
||||
|
||||
strategy.authenticate(req, { session: false });
|
||||
strategy.authenticate(req, {
|
||||
session: false,
|
||||
scope: this.scope,
|
||||
});
|
||||
} catch (err) {
|
||||
return this.error(err);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user