이번에는 쿠키를 사용하여 로그인 상태를 유지하는 단계에 대해 자세히 설명하겠습니다. 쿠키를 사용하여 로그인 상태를 유지할 때 주의 사항은 무엇인가요?
이번에는 나중에 사용할 웹사이트 로그인의 작은 예를 들어보겠습니다. 이 예에서는 쿠키, HTML 양식 및 POST 데이터 본문(본문) 구문 분석을 사용합니다.
첫 번째 버전에서는 사용자 데이터가 js 파일에 기록되었습니다. 두 번째 버전에서는 사용자 데이터를 저장하기 위해 MongoDB를 도입합니다.
예제 준비
1. express를 사용하여 애플리케이션을 만듭니다.
다음 명령 순서:
express LoginDemo cd LoginDemo npm install
2. 로그인 페이지의 jade 템플릿은 login.jade입니다. 내용은 다음과 같습니다.
doctype html html head meta(charset='UTF-8') title 登录 link(rel='stylesheet', href='/stylesheets/login.css') body .form-container p.form-header 登录 form(action='login', method='POST', align='center') table tr td label(for='user') 账号: td input#user(type='text', name='login_username') tr td label(for='pwd') 密码: td input#pwd(type='password', name='login_password') tr td(colspan='2', align='right') input(type='submit', value='登录') p #{msg}login.jade는 views 디렉토리에 있습니다. login.jade에 중국어 문자를 하드 코딩했습니다. 파일은 UTF-8로 인코딩되었습니다. 이 템플릿의 끝은 로그인
오류 메시지
를 표시하는 동적 메시지이며 msg 변수는 애플리케이션에 의해 전달됩니다.로그인 페이지인 login.css 파일에 간단한 CSS를 작성했는데 내용은 다음과 같습니다.
form { margin: 12px; } a { color: #00B7FF; } p.form-container { display: inline-block; border: 6px solid steelblue; width: 280px; border-radius: 10px; margin: 12px; } p.form-header { margin: 0px; font: 24px bold; color: white; background: steelblue; text-align: center; } input[type=submit]{ font: 18px bold; width: 120px; margin-left: 12px; }login.css를 public/stylesheets 디렉토리에 넣어주세요.
3. 프로필 페이지
로그인에 성공하면 구성 페이지가 표시됩니다. profile.jade 페이지 내용:
doctype html html head meta(charset='UTF-8') title= title body p #{msg} p #{lastTime} p a(href='/logout') 退出profile.jade가 views 디렉토리에 있습니다. 프로필 페이지에는 성공적인 로그인 메시지가 표시되고 마지막 로그인 시간도 표시되며 마지막으로 로그아웃 링크가 제공됩니다.
4. App.js 변경
사용자가 로그인하지 않고 웹사이트를 방문하면 자동으로 로그인 페이지로 이동할 수 있도록 app.js를 변경했습니다. 새로운 app.js의 내용은 다음과 같습니다.
var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var users = require('./routes/users'); var app = express(); // view engine setup app.set('views', path.join(dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(dirname, 'public'))); app.all('*', users.requireAuthentication); app.use('/', users); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handlers // development error handler // will print stacktrace if (app.get('env') === 'development') { app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: err }); }); } // production error handler // no stacktraces leaked to user app.use(function(err, req, res, next) { res.status(err.status || 500); res.render('error', { message: err.message, error: {} }); }); module.exports = app;
5. users.js
users.js를 수정해서 인증, 로그인, 로그아웃 등의 로직을 넣었습니다. 먼저 사용자를 전환해야 합니다. Node.js를 UTF-8로 인코딩합니다(죄송합니다. 한자는 하드 코딩되어 있습니다). 내용:
var express = require('express'); var router = express.Router(); var crypto = require('crypto'); function hashPW(userName, pwd){ var hash = crypto.createHash('md5'); hash.update(userName + pwd); return hash.digest('hex'); } // just for tutorial, it's bad really var userdb = [ { userName: "admin", hash: hashPW("admin", "123456"), last: "" }, { userName: "foruok", hash: hashPW("foruok", "888888"), last: "" } ]; function getLastLoginTime(userName){ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ return user.last; } } return ""; } function updateLastLoginTime(userName){ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ user.last = Date().toString(); return; } } } function authenticate(userName, hash){ for(var i = 0; i < userdb.length; ++i){ var user = userdb[i]; if(userName === user.userName){ if(hash === user.hash){ return 0; }else{ return 1; } } } return 2; } function isLogined(req){ if(req.cookies["account"] != null){ var account = req.cookies["account"]; var user = account.account; var hash = account.hash; if(authenticate(user, hash)==0){ console.log(req.cookies.account.account + " had logined."); return true; } } return false; }; router.requireAuthentication = function(req, res, next){ if(req.path == "/login"){ next(); return; } if(req.cookies["account"] != null){ var account = req.cookies["account"]; var user = account.account; var hash = account.hash; if(authenticate(user, hash)==0){ console.log(req.cookies.account.account + " had logined."); next(); return; } } console.log("not login, redirect to /login"); res.redirect('/login?'+Date.now()); }; router.post('/login', function(req, res, next){ var userName = req.body.login_username; var hash = hashPW(userName, req.body.login_password); console.log("login_username - " + userName + " password - " + req.body.login_password + " hash - " + hash); switch(authenticate(userName, hash)){ case 0: //success var lastTime = getLastLoginTime(userName); updateLastLoginTime(userName); console.log("login ok, last - " + lastTime); res.cookie("account", {account: userName, hash: hash, last: lastTime}, {maxAge: 60000}); res.redirect('/profile?'+Date.now()); console.log("after redirect"); break; case 1: //password error console.log("password error"); res.render('login', {msg:"密码错误"}); break; case 2: //user not found console.log("user not found"); res.render('login', {msg:"用户名不存在"}); break; } }); router.get('/login', function(req, res, next){ console.log("cookies:"); console.log(req.cookies); if(isLogined(req)){ res.redirect('/profile?'+Date.now()); }else{ res.render('login'); } }); router.get('/logout', function(req, res, next){ res.clearCookie("account"); res.redirect('/login?'+Date.now()); }); router.get('/profile', function(req, res, next){ res.render('profile',{ msg:"您登录为:"+req.cookies["account"].account, title:"登录成功", lastTime:"上次登录:"+req.cookies["account"].last }); }); module.exports = router;보시다시피 저는 admin과 foruok라는 두 개의 계정을 내장했습니다. 로그인 시 이 두 계정을 확인하고 올바르지 않으면 오류를 신고하겠습니다. 좋아, "npm start"를 실행하고 브라우저에서 "http://localhost:3000"을 열면 다음 효과를 볼 수 있습니다.
여러 번 시도하고 로그인하고 로그아웃하고 다시 로그인하세요. , 효과는 다음과 같습니다.
자, 이것이 이 예의 효과입니다. 다음으로 사용된 개념과 일부 코드를 설명하겠습니다.
예제에서는 HTML 양식을 사용하여 사용자 이름과 비밀번호를 받습니다. 입력 요소 유형이 제출되면 이를 클릭하면 브라우저가 데이터 형식을 지정합니다. 양식을 특정 형식으로 구성한 후 본문으로 인코딩하고 지정된 서버 주소로 POST합니다. 사용자 이름과 비밀번호는 HTML 요소
의 name 속성 값을 통해 서버 측에서 찾을 수 있습니다.//加载body-parser模块 var bodyParser = require('body-parser'); ... //应用中间件 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false }));/login 경로에서 POST 요청을 처리하기 위한 코드는 "router.post('/login'..."에서 시작하는 users.js에 있습니다( 94 좋습니다. 마크다운이 자동으로 코드에 줄 번호를 삽입할 수 있다면 좋을 것입니다.) 로그인 양식에서 사용자 이름을 참조하는 코드는 다음과 같습니다:
var userName = req.body.login_username;express.Request 객체 req에 구문 분석된 본문이 있음에 유의하세요. , login_username을 사용합니다. Login_username은 HTML의 입력 요소 이름 속성 값도 비슷합니다.
cookie,按我的理解,就是服务器发给浏览器的一张门票,要访问服务器内容,可以凭票入场,享受某种服务。服务器可以在门票上记录一些信息,从技术角度讲,想记啥记啥。当浏览器访问服务器时,HTTP头部把cookie信息带到服务器,服务器解析出来,校验当时记录在cookie里的信息。
HTTP协议本身是无状态的,而应用服务器往往想保存一些状态,cookie应运而生,由服务器颁发,通过HTTP头部传给浏览器,浏览器保存到本地。后续访问服务器时再通过HTTP头部传递给服务器。这样的交互,服务器就可以在cookie里记录一些用户相关的信息,比如是否登录了,账号了等等,然后就可以根据这些信息做一些动作,比如我们示例中的持久登录的实现,就利用了cookie。还有一些电子商务网站,实现购物车时也可能用到cookie。
cookie存储的是一些key-value对。在express里,Request和Response都有cookie相关的方法。Request实例req的cookies属性,保存了解析出的cookie,如果浏览器没发送cookie,那这个cookies对象就是一个空对象。
express有个插件,cookie-parser,可以帮助我们解析cookie。express生成的app.js已经自动为我们配置好了。相关代码:
var cookieParser = require('cookie-parser'); ... app.use(cookieParser());
express的Response对象有一个cookie方法,可以回写给浏览器一个cookie。
下面的代码发送了一个名字叫做“account”的cookie,这个cookie的值是一个对象,对象内有三个属性。
复制代码 代码如下:
res.cookie("account", {account: userName, hash: hash, last: lastTime}, {maxAge: 60000});
res.cookie()方法原型如下:
res.cookie(name, value [, options])
文档在这里:http://expressjs.com/4x/api.html。
浏览器会解析HTTP头部里的cookie,根据过期时间决定保存策略。当再次访问服务器时,浏览器会把cookie带给服务器。服务器使用cookieParser解析后保存在Request对象的cookies属性里,req.cookies本身是一个对象,解析出来的cookie,会被关联到req.cookies的以cookie名字命名的属性上。比如示例给cookie起的名字叫account,服务端解析出的cookie,就可以通过req.cookies.account来访问。注意req.cookies.account本身既可能是简单的值也可能是一个对象。在示例中通过res.cookie()发送的名为account的cookie,它的值是一个对象,在这种情况下,服务器这边从HTTP请求中解析出的cookie也会被组装成一个对象,所以我们通过req.cookies.account.account就可以拿到浏览器通过cookie发过来的用户名。但如果浏览器没有发送名为“account”的cookie,那req.cookies.account.hash这种访问就会抛异常,所以我在代码里使用req.cookies[“account”]这种方式来检测是否有account这个cookie。
持久登录
如果用户每次访问一个需要鉴权的页面都要输入用户名和密码来登录,那就太麻烦了。所以,很多现代的网站都实现了持久登录。我的示例使用cookie简单实现了持久登录。
在处理/login路径上的POST请求时,如果登录成功,就把用户名、一个hash值、还有上次登录时间保存在cookie里,并且设置cookie的有效期为60秒。这样在60秒有效期内,浏览器后续的访问就会带cookie,服务端代码从cookie里验证用户名和hash值,让用户保持登录状态。当过了60秒,浏览器就不再发送cookie,服务端就认为需要重新登录,将用户重定向到login页面。
现在服务端的用户信息就简单的放在js代码里了,非常丑陋,下次我们引入MongoDB,把用户信息放在数据库里。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 로그인 상태를 유지하기 위해 쿠키를 사용하는 자세한 단계의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!