๐ก ์ ๋ณด ์ถ์ฒ
- passport-official website : Click Here
- github-passport : Click Here
- npm-passport : Click Here
๐ ๊ณต์ ํํ์ด์ง Documentation ๋ฒ์ญ
http://www.passportjs.org/docs/
๐ Overview
app.post(
'/login',
passport.authenticate(
'local',
{
successRedirect: '/',
failureRedirect: '/login'
}
)
);
๐ Authenticate
- ๊ทธ๋ฅ ๋ผ์ฐํฐ์ ๋ฏธ๋ค์จ์ด์ฒ๋ผ ์ฐ๋ฉด ๋๋ค.
- strategy๋ง ์ ํด์ ์๋ ค์ฃผ๋ฉด ๋๋ค.
- ๋ง์ฝ ์ธ์ฆ์ด ์คํจํ๋ฉด passport๋ 401 Unauthorized๋ฅผ ๋ฐํํ๋ค.
- ์ธ์ฆ์ด ์ฑ๊ณตํ๋ฉฐ req.user์ user ์ ๋ณด๊ฐ ๋ด๊ธฐ๊ณ next()๊ฐ ํธ์ถ๋๋ค.
- flash message ๊ธฐ๋ฅ์ req.flash()๋ฅผ ์ฌ์ฉํ๋ค.
- ์ด๋ Express 2 ๋ฒ์ ์๋ ๋ด์ฅ๋์ด ์์ง๋ง, Express 3๋ฒ์ ์๋ ์๊ธฐ ๋๋ฌธ์ connect-flash๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
var flash = require('connect-flash'); app.use(flash());
app.post('/login',
passport.authenticate('local'),
function(req, res) {
res.redirect('/users/' + req.user.username);
});
app.post('/login',
passport.authenticate(
'local',
{
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}
));
passport.authenticate('local', { failureFlash: 'Invalid username.' });
passport.authenticate('local', { successFlash: 'Welcome!' });
app.get('/api/users/me',
passport.authenticate('basic', { session: false }),
function(req, res) {
res.json({ id: req.user.id, username: req.user.username });
});
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
- strategy, app middleware, sessions(optional) ์ธ ๊ฐ์ง๋ฅผ ์ค์ ํด์ผํ๋ค.
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
var session = require("express-session");
var bodyParser = require("body-parser");
app.use(express.static("public"));
app.use(session({ secret: "cats" }));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
๐ Username & Password
- the most widely used way for websites is the "passport-local"
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
{
usernameField: 'email',
passwordField: 'passwd'
},
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
app.post('/login',
passport.authenticate(
'local',
{
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}
)
);
๐ OpenID
- openID๋ ์ฌ์ฉ์์ openID Provider๋ฅผ ํตํด ์ธ์ฆ์ ์งํํ๋ ๋ก๊ทธ์ธ ๋ฐฉ์์ด๋ค.
npm install passport-openID
๊ฐ ํ์ํ๋ค.
var passport = require('passport');
var OpenIDStrategy = require('passport-openid').Strategy;
passport.use(new OpenIDStrategy({
returnURL: 'http://www.example.com/auth/openid/return',
realm: 'http://www.example.com/'
},
function(identifier, done) {
User.findOrCreate({ openId: identifier }, function(err, user) {
done(err, user);
});
}
));
app.post('/auth/openid', passport.authenticate('openid'));
app.get('/auth/openid/return',
passport.authenticate('openid', { successRedirect: '/',
failureRedirect: '/login' }));
passport.use(new OpenIDStrategy({
returnURL: 'http://www.example.com/auth/openid/return',
realm: 'http://www.example.com/',
profile: true
},
function(identifier, profile, done) {
}
));
<form action="/auth/openid" method="post">
<div>
<label>OpenID:</label>
<input type="text" name="openid_identifier"/><br/>
</div>
<div>
<input type="submit" value="Sign In"/>
</div>
</form>
๐ OAuth 1.0
- OAuth๋ API ์ ๊ทผ์ ํ๊ฐํด์ฃผ๋ ํ์คํ๋ ํ๋กํ ์ฝ์ด๋ค.
npm install passport-oauth
var passport = require('passport');
var OAuthStrategy = require('passport-oauth').OAuthStrategy;
passport.use('provider', new OAuthStrategy({
requestTokenURL: 'https://www.provider.com/oauth/request_token',
accessTokenURL: 'https://www.provider.com/oauth/access_token',
userAuthorizationURL: 'https://www.provider.com/oauth/authorize',
consumerKey: '123-456-789',
consumerSecret: 'shhh-its-a-secret'
callbackURL: 'https://www.example.com/auth/provider/callback'
},
function(token, tokenSecret, profile, done) {
User.findOrCreate(..., function(err, user) {
done(err, user);
});
}
));
app.get('/auth/provider', passport.authenticate('provider'));
app.get('/auth/provider/callback',
passport.authenticate('provider', { successRedirect: '/',
failureRedirect: '/login' }));
<a href="/auth/provider">Log In with OAuth Provider</a>
๐ OAuth 2.0
- OAuth 1.0 ๊ณผ ์ค์ ์ํฌํ๋ก์ฐ๋ ๊ฐ์ง๋ง, ์ด๊ธฐ ๋ฒ์ ์ ๋จ์ ๋ค์ ๊ฐ์ ํด๋์๋ค.
var passport = require('passport')
, OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
passport.use('provider', new OAuth2Strategy({
authorizationURL: 'https://www.provider.com/oauth2/authorize',
tokenURL: 'https://www.provider.com/oauth2/token',
clientID: '123-456-789',
clientSecret: 'shhh-its-a-secret'
callbackURL: 'https://www.example.com/auth/provider/callback'
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate(..., function(err, user) {
done(err, user);
});
}
));
app.get('/auth/provider', passport.authenticate('provider'));
app.get('/auth/provider/callback',
passport.authenticate('provider', { successRedirect: '/',
failureRedirect: '/login' }));
app.get('/auth/provider',
passport.authenticate('provider', { scope: ['email', 'sms'] })
);
๐ User Profile
- provider๋ฅผ ํตํด ์ ์ ๊ด๋ฆฌ๋ฅผ ํ๋ ๊ฒฝ์ฐ, ์ ์ ์ ๋ณด๊ฐ ์ ๊ฐ๊ฐ์ธ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
- passport๋ ์ด๋ฅผ ์ด๋์ ๋ ํ์คํํ์ฌ ์ ๊ณตํ๊ณ ์๋ค.
๐ง Google
npm install passport-google-oauth
- google develope console์์ ID์ Key๋ฅผ ๋ฐ๊ธ ๋ฐ์์ผํ๋ค.
- ๊ทธ๋ฆฌ๊ณ Google+ API ๋ฅผ ํ์ฑํํด๋ผ.
- ์ ๊ทธ๋ฌ๋ฉด ์ ์ ์ ์ ์ ์ ๋ณด๋ฅผ ๋ชป ๋ฐ์ ์ ์๋ค.
OAuth 1.0 - Google
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuthStrategy;
passport.use(new GoogleStrategy({
consumerKey: GOOGLE_CONSUMER_KEY,
consumerSecret: GOOGLE_CONSUMER_SECRET,
callbackURL: "http://www.example.com/auth/google/callback"
},
function(token, tokenSecret, profile, done) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return done(err, user);
});
}
));
app.get('/auth/google',
passport.authenticate('google', { scope: 'https://www.google.com/m8/feeds' });
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
OAuth 2.0 - Google
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://www.example.com/auth/google/callback"
},
function(accessToken, refreshToken, profile, done) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return done(err, user);
});
}
));
app.get('/auth/google',
passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/plus.login'] }));
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
๐ Basic & Digest
- ์ด ๋ ์คํค๋ง๋ ์์ด๋์ ํจ์ค์๋๋ฅผ ์ด์ฉํ์ฌ ์ ์ ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ API endpoint๋ฅผ ๋ณดํธํ๋ค.
- ํดํน์ ์ทจ์ฝํ ์๋น์ค์ ๊ฒฝ์ฐ OAuth 2.0์ ์ฌ์ฉํ ๊ฒ์ ์ถ์ฒํ๋ค.
- Basic๊ณผ Digest ์คํค๋ง๋ passport-http ๋ชจ๋์ ํตํด ์ฌ์ฉ๊ฐ๋ฅํ๋ค.
passport.use(new BasicStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.validPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
app.get('/api/me',
passport.authenticate('basic', { session: false }),
function(req, res) {
res.json(req.user);
});
passport.use(new DigestStrategy({ qop: 'auth' },
function(username, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
return done(null, user, user.password);
});
},
function(params, done) {
done(null, true)
}
));
app.get('/api/me',
passport.authenticate('digest', { session: false }),
function(req, res) {
res.json(req.user);
});
๐คฉ OAuth 2.0
- OAuth 2.0 ์ ํ ํฐ์ ์ฌ์ฉํ๋ค.
- ์ด๋ ๋ ๊ฐ์ง ํฐ ์ฅ์ ์ด ์๋ค.
- ์ฒซ์งธ๋ก, ํ ํฐ์ ์ ์ ์ ์ด๋ฆ๊ณผ ํจ์ค์๋๋ฅผ ์ ์ฅํ ํ์๊ฐ ์๋ค.
- ๋์งธ๋ก, ํ ํฐ์๋ ์ ์ฝ์ ๋ ์ ์๋ค(์ฝ๊ธฐ-์ ์ฉ ์ฒ๋ผ..)
npm install passport-http-bearer
passport.use(new BearerStrategy(
function(token, done) {
User.findOne({ token: token }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
return done(null, user, { scope: 'read' });
});
}
));
app.get('/api/me',
passport.authenticate('bearer', { session: false }),
function(req, res) {
res.json(req.user);
});
๐ฅบ Login
- login ์ธ์
์ ๋ง๋ค๊ธฐ ์ํด login() ํจ์๋ฅผ ์ธ ์ ์๋ค.
- ๊ทธ๋ ๊ฒ ์ ์ฅ๋ user ์ ๋ณด๋ req.user๋ก ์ ๊ทผํ ์ ์๋ค.
- passport.authenticate() ๋ฏธ๋ค์จ์ด๋ฅผ ์ฐ๋ฉด req.login()์ด ์๋์ผ๋ก ์คํ๋๋ค.
- ๊ทธ๋์ ์ด ํจ์๋ ๋ณดํต ํ์๊ฐ์
๊ธฐ๋ฅ์ ๊ตฌํํ ๋๋ง ์ฌ์ฉ๋๋ค.
req.login(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + req.user.username);
});
๐ค Logout
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
๐ค Authorize
- google, facebook ๋ฑ์ ํตํด ๊ฐ์
ํ ํ์์ ํ๋๋ก ํตํฉํด์ผํ ๋๊ฐ ์๋ค.
- passport.authorize()์ผ๋ก ์ด๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
- ๊ทธ ์ ๋ณด๋ค์ req.account์ ์ ์ฅ๋๋ค.
app.get('/connect/twitter',
passport.authorize('twitter-authz', { failureRedirect: '/account' })
);
app.get('/connect/twitter/callback',
passport.authorize('twitter-authz', { failureRedirect: '/account' }),
function(req, res) {
var user = req.user;
var account = req.account;
account.userId = user.id;
account.save(function(err) {
if (err) { return self.error(err); }
self.redirect('/');
});
}
);
passport.use('twitter-authz', new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://www.example.com/connect/twitter/callback"
},
function(token, tokenSecret, profile, done) {
Account.findOne({ domain: 'twitter.com', uid: profile.id }, function(err, account) {
if (err) { return done(err); }
if (account) { return done(null, account); }
var account = new Account();
account.domain = 'twitter.com';
account.uid = profile.id;
var t = { kind: 'oauth', token: token, attributes: { tokenSecret: tokenSecret } };
account.tokens.push(t);
return done(null, account);
});
}
));
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: "http://www.example.com/auth/twitter/callback",
passReqToCallback: true
},
function(req, token, tokenSecret, profile, done) {
if (!req.user) {
} else {
}
}
));