增加twitter auth v1
This commit is contained in:
parent
1ea077ca93
commit
3691d000da
@ -16,10 +16,12 @@
|
|||||||
"author": "zhl",
|
"author": "zhl",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fastify/cookie": "^9.3.1",
|
||||||
"@fastify/cors": "^8.1.0",
|
"@fastify/cors": "^8.1.0",
|
||||||
"@fastify/formbody": "^7.3.0",
|
"@fastify/formbody": "^7.3.0",
|
||||||
"@fastify/helmet": "^10.0.1",
|
"@fastify/helmet": "^10.0.1",
|
||||||
"@fastify/jwt": "^6.3.2",
|
"@fastify/jwt": "^6.3.2",
|
||||||
|
"@fastify/session": "^10.7.2",
|
||||||
"@fastify/view": "^7.4.1",
|
"@fastify/view": "^7.4.1",
|
||||||
"@typegoose/typegoose": "9.12.1",
|
"@typegoose/typegoose": "9.12.1",
|
||||||
"axios": "^1.1.3",
|
"axios": "^1.1.3",
|
||||||
@ -34,6 +36,7 @@
|
|||||||
"mongoose-findorcreate": "^3.0.0",
|
"mongoose-findorcreate": "^3.0.0",
|
||||||
"nanoid": "^3.1.23",
|
"nanoid": "^3.1.23",
|
||||||
"node-schedule": "^2.1.1",
|
"node-schedule": "^2.1.1",
|
||||||
|
"oauth": "^0.10.0",
|
||||||
"tracer": "^1.1.6"
|
"tracer": "^1.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -29,6 +29,16 @@ export class ApiServer {
|
|||||||
console.log('version::' + process.version)
|
console.log('version::' + process.version)
|
||||||
}
|
}
|
||||||
private registerPlugins() {
|
private registerPlugins() {
|
||||||
|
this.server.register(require('@fastify/cookie'))
|
||||||
|
this.server.register(require('@fastify/session'), {
|
||||||
|
cookieName: 'sessionId',
|
||||||
|
secret: process.env.COOKIE_SECRET,
|
||||||
|
cookie: { secure: false },
|
||||||
|
expires: 900000,
|
||||||
|
})
|
||||||
|
this.server.addHook('preHandler', (request, reply, next) => {
|
||||||
|
next()
|
||||||
|
})
|
||||||
this.server.register(require('@fastify/formbody'))
|
this.server.register(require('@fastify/formbody'))
|
||||||
this.server.register(zReqParserPlugin)
|
this.server.register(zReqParserPlugin)
|
||||||
this.server.register(helmet, {
|
this.server.register(helmet, {
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
|
import { ZError } from 'common/ZError'
|
||||||
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
import BaseController, { ROLE_ANON } from 'common/base.controller'
|
||||||
import { role, router } from 'decorators/router'
|
import { role, router } from 'decorators/router'
|
||||||
import logger from 'logger/logger'
|
import logger from 'logger/logger'
|
||||||
import { AuthRecord } from 'modules/AuthRecord'
|
import { AuthRecord } from 'modules/AuthRecord'
|
||||||
import { exchangeTwitterCodeForToken, getTwitterUserInfo } from 'services/twitter.svr'
|
import {
|
||||||
|
exchangeTwitterCodeForToken,
|
||||||
|
getOAuthAccessTokenWith,
|
||||||
|
getOAuthRequestToken,
|
||||||
|
getTwitterUserInfo,
|
||||||
|
} from 'services/twitter.svr'
|
||||||
import { parseOauthState } from 'utils/net.util'
|
import { parseOauthState } from 'utils/net.util'
|
||||||
|
|
||||||
class TwitterController extends BaseController {
|
class TwitterController extends BaseController {
|
||||||
@ -51,4 +57,51 @@ class TwitterController extends BaseController {
|
|||||||
}
|
}
|
||||||
return res.view('/templates/twitter_redirect.ejs')
|
return res.view('/templates/twitter_redirect.ejs')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@role(ROLE_ANON)
|
||||||
|
@router('get /twitter/oauth/:address')
|
||||||
|
async twitterOauth1(req, res) {
|
||||||
|
let method = 'authenticate'
|
||||||
|
let { address } = req.params
|
||||||
|
if (!address) {
|
||||||
|
throw new ZError(10, 'address needed')
|
||||||
|
}
|
||||||
|
address = address.toLowerCase()
|
||||||
|
// @ts-ignore
|
||||||
|
const { oauthRequestToken, oauthRequestTokenSecret } = await getOAuthRequestToken()
|
||||||
|
console.log(`/oauth/twitter} ->`, { oauthRequestToken, oauthRequestTokenSecret })
|
||||||
|
req.session.oauthRequestToken = oauthRequestToken
|
||||||
|
req.session.oauthRequestTokenSecret = oauthRequestTokenSecret
|
||||||
|
req.session.address = address
|
||||||
|
const authorizationUrl = `https://api.twitter.com/oauth/${method}?oauth_token=${oauthRequestToken}`
|
||||||
|
console.log('redirecting user to ', authorizationUrl)
|
||||||
|
res.redirect(authorizationUrl)
|
||||||
|
}
|
||||||
|
// for twitter oauth v1.0
|
||||||
|
@role(ROLE_ANON)
|
||||||
|
@router('get /twitter/callback')
|
||||||
|
async twitterOauth1Callback(req, res) {
|
||||||
|
const { address, oauthRequestToken, oauthRequestTokenSecret } = req.session
|
||||||
|
console.log('request.query', req.query)
|
||||||
|
const { oauth_verifier: oauthVerifier } = req.query
|
||||||
|
const { oauthAccessToken, oauthAccessTokenSecret, results } = await getOAuthAccessTokenWith({
|
||||||
|
oauthRequestToken,
|
||||||
|
oauthRequestTokenSecret,
|
||||||
|
oauthVerifier,
|
||||||
|
})
|
||||||
|
const { user_id: userId /*, screen_name */ } = results
|
||||||
|
console.log('userId:', userId)
|
||||||
|
const record = await AuthRecord.insertOrUpdate(
|
||||||
|
{ address, platform: 4 },
|
||||||
|
{ address, platform: 4, $inc: { version: 1 } },
|
||||||
|
)
|
||||||
|
record.nickname = results.screen_name
|
||||||
|
record.username = results.screen_name
|
||||||
|
record.openId = results.user_id
|
||||||
|
record.accessToken = oauthAccessToken
|
||||||
|
record.refreshToken = oauthAccessTokenSecret
|
||||||
|
record.tokenType = 'oauth1'
|
||||||
|
await record.save()
|
||||||
|
return res.view('/templates/twitter_redirect.ejs')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const consumerKey = process.env.TWITTER_CLIENT_ID
|
const consumerKey = process.env.TWITTER_CLIENT_ID
|
||||||
const consumerSecret = process.env.TWITTER_CLIENT_SECRET
|
const consumerSecret = process.env.TWITTER_CLIENT_SECRET
|
||||||
|
import { OAuth } from 'oauth'
|
||||||
|
import { promisify } from 'util'
|
||||||
|
|
||||||
export async function exchangeTwitterCodeForToken(code: string, vcode: string) {
|
export async function exchangeTwitterCodeForToken(code: string, vcode: string) {
|
||||||
const url = 'https://api.twitter.com/2/oauth2/token'
|
const url = 'https://api.twitter.com/2/oauth2/token'
|
||||||
@ -63,3 +65,49 @@ export async function getTwitterUserInfo(accessToken: string) {
|
|||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oauthConsumer = new OAuth(
|
||||||
|
'https://api.twitter.com/oauth/request_token',
|
||||||
|
'https://api.twitter.com/oauth/access_token',
|
||||||
|
process.env.TWITTER_API_KEY,
|
||||||
|
process.env.TWITTER_API_SECRET,
|
||||||
|
'1.0A',
|
||||||
|
process.env.TWITTER_OAUTH1_CB,
|
||||||
|
'HMAC-SHA1',
|
||||||
|
)
|
||||||
|
|
||||||
|
export async function getOAuthAccessTokenWith({
|
||||||
|
oauthRequestToken,
|
||||||
|
oauthRequestTokenSecret,
|
||||||
|
oauthVerifier,
|
||||||
|
}: any = {}): Promise<any> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
oauthConsumer.getOAuthAccessToken(
|
||||||
|
oauthRequestToken,
|
||||||
|
oauthRequestTokenSecret,
|
||||||
|
oauthVerifier,
|
||||||
|
function (error, oauthAccessToken, oauthAccessTokenSecret, results) {
|
||||||
|
return error
|
||||||
|
? reject(new Error('Error getting OAuth access token'))
|
||||||
|
: resolve({ oauthAccessToken, oauthAccessTokenSecret, results })
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export async function getOAuthRequestToken() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
oauthConsumer.getOAuthRequestToken(function (error, oauthRequestToken, oauthRequestTokenSecret, results) {
|
||||||
|
return error
|
||||||
|
? reject(new Error('Error getting OAuth request token'))
|
||||||
|
: resolve({ oauthRequestToken, oauthRequestTokenSecret, results })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function oauthGetUserById(userId, { oauthAccessToken, oauthAccessTokenSecret }: any = {}) {
|
||||||
|
return promisify(oauthConsumer.get.bind(oauthConsumer))(
|
||||||
|
`https://api.twitter.com/1.1/users/show.json?user_id=${userId}`,
|
||||||
|
oauthAccessToken,
|
||||||
|
oauthAccessTokenSecret,
|
||||||
|
).then(body => JSON.parse(body))
|
||||||
|
}
|
||||||
|
26
yarn.lock
26
yarn.lock
@ -109,6 +109,14 @@
|
|||||||
ajv-formats "^2.1.1"
|
ajv-formats "^2.1.1"
|
||||||
fast-uri "^2.0.0"
|
fast-uri "^2.0.0"
|
||||||
|
|
||||||
|
"@fastify/cookie@^9.3.1":
|
||||||
|
version "9.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fastify/cookie/-/cookie-9.3.1.tgz#48b89a356a23860c666e2fe522a084cc5c943d33"
|
||||||
|
integrity sha512-h1NAEhB266+ZbZ0e9qUE6NnNR07i7DnNXWG9VbbZ8uC6O/hxHpl+Zoe5sw1yfdZ2U6XhToUGDnzQtWJdCaPwfg==
|
||||||
|
dependencies:
|
||||||
|
cookie-signature "^1.1.0"
|
||||||
|
fastify-plugin "^4.0.0"
|
||||||
|
|
||||||
"@fastify/cors@^8.1.0":
|
"@fastify/cors@^8.1.0":
|
||||||
version "8.3.0"
|
version "8.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fastify/cors/-/cors-8.3.0.tgz#f03d745731b770793a1a15344da7220ca0d19619"
|
resolved "https://registry.yarnpkg.com/@fastify/cors/-/cors-8.3.0.tgz#f03d745731b770793a1a15344da7220ca0d19619"
|
||||||
@ -161,6 +169,14 @@
|
|||||||
fastify-plugin "^4.0.0"
|
fastify-plugin "^4.0.0"
|
||||||
steed "^1.1.3"
|
steed "^1.1.3"
|
||||||
|
|
||||||
|
"@fastify/session@^10.7.2":
|
||||||
|
version "10.7.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fastify/session/-/session-10.7.2.tgz#8c4441133257075fc7eb79ce31b9a9d594e32ea8"
|
||||||
|
integrity sha512-PezR26nY8FMmAs4cww5rpnVyRkPDv2WQcVBLEKrtLTQy8mjL+twUKv9TLo/SXZYHZOIETzmquWoLYlnY3dSb+w==
|
||||||
|
dependencies:
|
||||||
|
fastify-plugin "^4.0.0"
|
||||||
|
safe-stable-stringify "^2.3.1"
|
||||||
|
|
||||||
"@fastify/view@^7.4.1":
|
"@fastify/view@^7.4.1":
|
||||||
version "7.4.1"
|
version "7.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/@fastify/view/-/view-7.4.1.tgz#265daba48386a5d3f69dfc446af468d72e0a8757"
|
resolved "https://registry.yarnpkg.com/@fastify/view/-/view-7.4.1.tgz#265daba48386a5d3f69dfc446af468d72e0a8757"
|
||||||
@ -727,6 +743,11 @@ concat-map@0.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||||
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
|
||||||
|
|
||||||
|
cookie-signature@^1.1.0:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.1.tgz#790dea2cce64638c7ae04d9fabed193bd7ccf3b4"
|
||||||
|
integrity sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==
|
||||||
|
|
||||||
cookie@^0.5.0:
|
cookie@^0.5.0:
|
||||||
version "0.5.0"
|
version "0.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
|
||||||
@ -1763,6 +1784,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
|
||||||
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
|
||||||
|
|
||||||
|
oauth@^0.10.0:
|
||||||
|
version "0.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.10.0.tgz#3551c4c9b95c53ea437e1e21e46b649482339c58"
|
||||||
|
integrity sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==
|
||||||
|
|
||||||
obliterator@^2.0.1:
|
obliterator@^2.0.1:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816"
|
resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user