Cet article présente principalement l'exemple de node.js+captchapng+jsonwebtoken pour implémenter la vérification de connexion. Il a une certaine valeur de référence. Ceux qui sont intéressés peuvent en apprendre davantage.
En ce qui concerne la vérification de connexion, tout le monde peut certainement y penser. Le code de vérification est 12306. 12306 s'est donné beaucoup de mal pour prévenir la fraude aux billets, et le code de vérification est devenu de plus en plus difficile à identifier, et éventuellement même les humains pourraient ne pas être en mesure de l'identifier.
Aujourd'hui, l'éditeur vous expliquera comment implémenter le code de vérification d'image dans le nœud et utiliser un jeton pour vérifier la connexion. En étudiant cet article, vous apprendrez :
1. Utilisez captchapng pour générer le code de vérification d'image
2. Utilisez jsonwebtoken pour implémenter la vérification de connexion
1 , Génération de code de vérification d'image (tous les codes à la fin)
Tout d'abord, jetons un coup d'œil au processus Dans la première étape, le serveur doit générer aléatoirement un ensemble de quatre. chiffres.
La deuxième étape consiste à dessiner ces quatre chiffres sur toile pour générer une image.
La troisième étape consiste à enregistrer ces quatre chiffres à des fins de comparaison lorsque l'utilisateur renvoie les données.
Alors, où le sauvegarder ? Évidemment, afin de distinguer les utilisateurs, il est plus sûr de les enregistrer en session.
La première étape est d'avoir une page de connexion. Ici, nous utilisons toujours React,
login.tsx
import * as React from 'react' import * as ReactDom from 'react-dom' import {Link, browserHistory} from 'react-router'; import * as axios from 'axios'; export default class Login extends React.Component<any,any>{ constructor(props){ super(props) this.state = { userName : '', password : '', yzNoId : '', hash : Math.random() } } handleUserName(e) : any { this.setState({ userName : e.target.value }) } handlePassword(e) : any { this.setState({ password : e.target.value }) } handleYzId(e) : any { this.setState({ yzNoId : e.target.value }) } render(){ const { userName, password, yzNoId } = this.state; return( <p> <p className="nav-wrap"> <ul className="nav"> <li><Link to="/home">首页</Link></li> <li><Link to="/imgLoad">上传</Link></li> <li><Link to="/login">登陆</Link></li> </ul> </p> <p className="content"> <p className="login-warp"> <p> <input type="text" className="username" value={userName} onChange={this.handleUserName.bind(this)} placeholder="用户名"/> </p> <p> <input type="text" className="password" value={password} onChange={this.handlePassword.bind(this)} placeholder="密码"/> </p> <p> <input type="text" className="yz" value={yzNoId} onChange={this.handleYzId.bind(this)} placeholder="验证码"/> <img src={"http://localhost:3000/captcha"} className="yz-img" /> </p> <p> <input type="button" className="submit" value="登陆" onClick={this.sbumit.bind(this,{userName:userName,password:password,captcha:yzNoId})} /> </p> </p> </p> </p> ) } }
La page ressemble à ceci
Nous devons envoyer une photo de vérification via le serveur.
router/index.js Ajoutez le code suivant
var Login = require('./controller/login'); var login = new Login; router.get('/captcha', login.captcha); router.post('/login',login.loginer); login是定义在控制器的一个类的实例,captcha,loginer是它的方法。分别是返回验证图片、登录验证。 controller/login.js var rf = require('fs'); var captchapng = require('captchapng'); class Login { constructor(){} captcha(req, res, next) { var str = parseInt(Math.random()*9000+1000); //随机生成数字 req.session.captcha = str; // 存入session var p = new captchapng(80, 30, str); //生成图片 p.color(0, 0, 0, 0); p.color(80, 80, 80, 255); var img = p.getBase64(); var imgbase64 = new Buffer(img, 'base64'); res.writeHead(200, { 'Content-Type': 'image/png' }); res.end(imgbase64); } loginer(req, res, next) { let captcha = req.body.captcha; let userName = req.body.userName; let password = req.body.password; if (captcha != req.session.captcha) { res.status(400).send({ message: '验证码错误' }); }else if(userName == "chenxuehui" && password == "123321"){ res.json({"code":100,"verson":true,"msg":"登陆成功","token":token}); }else{ res.json({"code":0,"verson":false,"msg":"密码错误"}); } } } module.exports = Login
La méthode captcha consiste à générer une image contenant quatre chiffres, puis L'image est enregistrée dans la session.
Référencez cette méthode dans router/index.js
router.get('/captcha', login.captcha);
C'est-à-dire si on accède à localhost:3000/captcha une image.
Avec cette connexion, nous pouvons obtenir l'image via l'attribut src de l'image, mais lorsque l'on clique sur l'image, elle doit être actualisée, nous devons donc ajouter un événement d'actualisation de clic. Insérez le code suivant dans login.tsx
setHash() { this.setState({ hash : Math.random() }) }
La balise img devient également
Copier le code Le code est la suivante :
🎜>
De cette façon, tant que vous cliquez sur img, un hachage sera généré aléatoirement, puis la nouvelle image sera appelée.
Ensuite, nous procédons à la vérification de la connexion.
import * as React from 'react' import * as ReactDom from 'react-dom' import {Link, browserHistory} from 'react-router'; import * as axios from 'axios'; export default class Login extends React.Component<any,any>{ constructor(props){ super(props) this.state = { userName : '', password : '', yzNoId : '', hash : Math.random() } } public async sbumit(params : any) : Promise<any>{ let res = await axios.post('http://localhost:3000/login',params); } handleUserName(e) : any { this.setState({ userName : e.target.value }) } handlePassword(e) : any { this.setState({ password : e.target.value }) } handleYzId(e) : any { this.setState({ yzNoId : e.target.value }) } setHash() { this.setState({ hash : Math.random() }) } render(){ const { userName, password, yzNoId } = this.state; return( <p> <p className="nav-wrap"> <ul className="nav"> <li><Link to="/home">首页</Link></li> <li><Link to="/imgLoad">上传</Link></li> <li><Link to="/login">登陆</Link></li> </ul> </p> <p className="content"> <p className="login-warp"> <p> <input type="text" className="username" value={userName} onChange={this.handleUserName.bind(this)} placeholder="用户名"/> </p> <p> <input type="text" className="password" value={password} onChange={this.handlePassword.bind(this)} placeholder="密码"/> </p> <p> <input type="text" className="yz" value={yzNoId} onChange={this.handleYzId.bind(this)} placeholder="验证码"/> <img src={"http://localhost:3000/captcha?aaa="+this.state.hash} className="yz-img" onClick={this.setHash.bind(this)} /> </p> <p> <input type="button" className="submit" value="登陆" onClick={this.sbumit.bind(this,{userName:userName,password:password,captcha:yzNoId})} /> </p> </p> </p> </p> ) } }
Lorsque l'utilisateur se connecte avec succès, il n'est pas nécessaire de se reconnecter la prochaine fois. Dans le passé, vous pouvez choisir une session ou un cookie. Ici, nous utilisons un jeton. Parce que nous avons désormais implémenté un développement séparé du front-end et du back-end, nous sommes plus enclins à créer une seule page et à utiliser Ajax pour créer des applications. Le token est le plus adapté à ce modèle de développement.
Vérification de connexion au jeton
Le jeton est une chaîne cryptée une fois la connexion réussie, il est renvoyé à l'utilisateur pour stockage. Ensuite, l'utilisateur apportera ce jeton lors de la demande. interface. Nous devons donc chiffrer le jeton.
Json Web Token est spécifiquement conçu pour résoudre ce problème. Le principe ne sera pas expliqué en détail. En fait, il s'agit d'obtenir une chaîne d'une certaine manière puis de la démêler d'une certaine manière. .
Lorsque l'utilisateur se connecte avec succès, créez un jeton et renvoyez-le à l'utilisateur.
Étape 2 : Une fois que l'utilisateur a obtenu le jeton, il doit enregistrer le jeton localement.
Étape 3 : Nous devons écrire une couche intermédiaire à chaque fois que l'utilisateur le demande, nous vérifions si le jeton porté par l'utilisateur est correct. Les données sont renvoyées correctement, l'avertissement est renvoyé de manière incorrecte.
Étape 2 : Enregistrez une fois que l'utilisateur l'a obtenu.
var rf = require('fs'); var jwt = require('jsonwebtoken'); var captchapng = require('captchapng'); var Tokens = require('../middleware/token') var t = new Tokens; class Login { constructor(){} captcha(req, res, next) { var str = parseInt(Math.random()*9000+1000); //随机生成数字 req.session.captcha = str; // 存入session var p = new captchapng(80, 30, str); //生成图片 p.color(0, 0, 0, 0); p.color(80, 80, 80, 255); var img = p.getBase64(); var imgbase64 = new Buffer(img, 'base64'); res.writeHead(200, { 'Content-Type': 'image/png' }); res.end(imgbase64); } loginer(req, res, next) { let captcha = req.body.captcha; let userName = req.body.userName; let password = req.body.password; if (captcha != req.session.captcha) { res.status(400).send({ message: '验证码错误' }); }else if(userName == "chenxuehui" && password == "123321"){ // 设置token var datas = {userName:"chenxuehui"} //调用../middleware/token 下方法设置 var token = t.setToken('cxh',300,datas) res.json({"code":100,"verson":true,"msg":"登陆成功","token":token}); }else{ res.json({"code":0,"verson":false,"msg":"密码错误"}); } } } module.exports = Login
Dans la méthode sbumit, nous mettons le jeton dans sesssonstorage.
Étape 3 : Configurez le middleware pour vérifier le jeton à chaque fois qu'il demande l'interface. Si l'analyse réussit, il sera ajouté à l'en-tête de la demande.
import * as React from 'react' import * as ReactDom from 'react-dom' import {Link, browserHistory} from 'react-router'; import * as axios from 'axios'; export default class Login extends React.Component<any,any>{ constructor(props){ super(props) this.state = { userName : '', password : '', yzNoId : '', hash : Math.random() } } public async sbumit(params : any) : Promise<any>{ let res = await axios.post('http://localhost:3000/login',params); if(res.data.verson){ sessionStorage.setItem('token',res.data.token); browserHistory.push("/home") } } handleUserName(e) : any { this.setState({ userName : e.target.value }) } handlePassword(e) : any { this.setState({ password : e.target.value }) } handleYzId(e) : any { this.setState({ yzNoId : e.target.value }) } setHash() { this.setState({ hash : Math.random() }) } render(){ const { userName, password, yzNoId } = this.state; return( <p> <p className="nav-wrap"> <ul className="nav"> <li><Link to="/home">首页</Link></li> <li><Link to="/imgLoad">上传</Link></li> <li><Link to="/login">登陆</Link></li> </ul> </p> <p className="content"> <p className="login-warp"> <p> <input type="text" className="username" value={userName} onChange={this.handleUserName.bind(this)} placeholder="用户名"/> </p> <p> <input type="text" className="password" value={password} onChange={this.handlePassword.bind(this)} placeholder="密码"/> </p> <p> <input type="text" className="yz" value={yzNoId} onChange={this.handleYzId.bind(this)} placeholder="验证码"/> <img src={"http://localhost:3000/captcha?aaa="+this.state.hash} className="yz-img" onClick={this.setHash.bind(this)} /> </p> <p> <input type="button" className="submit" value="登陆" onClick={this.sbumit.bind(this,{userName:userName,password:password,captcha:yzNoId})} /> </p> </p> </p> </p> ) } }
La méthode testToken consiste à vérifier le jeton et setToken consiste à définir le jeton méthode
S'il n'y a pas de demande de connexion, c'est comme ça
在 router/index.js
var express = require('express'); var router = express.Router(); var rf = require('fs'); var Login = require('./controller/login'); var Tokens = require('./middleware/token') var t = new Tokens; var login = new Login; //主页 router.get('/', function(req, res, next) { res.render("wap/index") }); //获取图片验证码 router.get('/captcha', login.captcha); //登录验证 router.post('/login',login.loginer); //请求数据时 t.testToken 验证token router.post('/list',t.testToken,function(req, res, next){ res.json({ //在请求信息里面拿到数据 username : req.userInfo.userName, success : true, result : [ { name:'1111111' }, { name :'22222' } ] }) }) module.exports = router;
我们在另一个页面调用list接口试一下
import * as axios from 'axios'; import { transToken } from '../decorator/index' class Home extends React.Component<any,any>{ constructor(props){ super(props) this.state = { data : '' } } async getList(): Promise<any>{ let token = sessionStorage.getItem('token'); const config = { // 请求头信息 headers: {'x-access-token': token} } let res = await axios.post('http://localhost:3000/list',{},config); if(!res.data.success){ browserHistory.push('/login'); return; } this.setState({ data : res.data }) } render(){ const { data } = this.state; return( <p> <p className="nav-wrap"> <ul className="nav"> <li><Link to="/home">首页</Link></li> <li><Link to="/imgLoad">上传</Link></li> <li><Link to="/login">登陆</Link></li> </ul> </p> <p className="content"> Home <span onClick={this.getList.bind(this)}>获取数据</span> <p>{ data ? data.result.map( (val,k) => { return <li key = {k}>{val.name}</li> }) : null }</p> </p> </p> ) } } export default Home
当调用getList时,如果此时没有登录res.data.success就会为false,则跳到登录页。
全部代码
node.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 session = require("express-session"); var ejs = require('ejs'); var index = require('./routes/index'); var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); // app.set('view engine', 'jade'); app.engine('html', ejs.__express); app.set('view engine', 'html'); app.use(session({ secret:"dabao", resave:false, saveUninitialized:true, cookie:{} })); // 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({limit: 5000000})); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, ''))); app.use('/', index); // 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 handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
index.js
var express = require('express'); var router = express.Router(); var rf = require('fs'); var Login = require('./controller/login'); var Tokens = require('./middleware/token') var t = new Tokens; var login = new Login; /* GET home page. */ router.get('/', function(req, res, next) { res.render("wap/index") }); router.post('/upLoadImg',function(req,res,next){ let imgData = req.body.imgData; console.log(imgData) let base64Data = imgData.replace(/^data:image\/\w+;base64,/, ""); let dataBuffer = new Buffer(base64Data, 'base64'); let timer = Number( new Date() ); console.log(timer) rf.writeFile("views/images/artCover"+timer+".png",dataBuffer, function(err) { if(err) { res.json({"code":400,"verson":false,"msg":err}); }else { res.json({"code":100,"verson":true,"url":"views/src/common/images/artCover/"+timer+".png"}); } }); }) router.get('/captcha', login.captcha); router.post('/login',login.loginer); router.post('/list',t.testToken,function(req, res, next){ // 先解析token console.log(req.userInfo) res.json({ username : req.userInfo.userName, success : true, result : [ { name:'1111111' }, { name :'22222' } ] }) }) module.exports = router;
controller/login.js
var rf = require('fs'); var jwt = require('jsonwebtoken'); var captchapng = require('captchapng'); var Tokens = require('../middleware/token') var t = new Tokens; class Login { constructor(){} captcha(req, res, next) { var str = parseInt(Math.random()*9000+1000); //随机生成数字 req.session.captcha = str; // 存入session var p = new captchapng(80, 30, str); //生成图片 p.color(0, 0, 0, 0); p.color(80, 80, 80, 255); var img = p.getBase64(); var imgbase64 = new Buffer(img, 'base64'); res.writeHead(200, { 'Content-Type': 'image/png' }); res.end(imgbase64); } loginer(req, res, next) { let captcha = req.body.captcha; let userName = req.body.userName; let password = req.body.password; if (captcha != req.session.captcha) { res.status(400).send({ message: '验证码错误' }); }else if(userName == "chenxuehui" && password == "123321"){ // 设置token var datas = {userName:"chenxuehui"} var token = t.setToken('cxh',300,datas) res.json({"code":100,"verson":true,"msg":"登陆成功","token":token}); }else{ res.json({"code":0,"verson":false,"msg":"密码错误"}); } } } module.exports = Login
middleware/token.js
var jwt = require('jsonwebtoken'); class Tokens { constructor(){} testToken(req,res,next) { var token = req.body.token || req.query.token || req.headers['x-access-token']; if(token) { jwt.verify(token, 'cxh' , function(err,decoded) { if(err) { return res.json({success:false,msg:'token错误'}) }else { req.userInfo = decoded; next() } }) }else { return res.status(403).send({success:false,msg:"没有token"}) } } setToken(name,time,data) { var jwtSecret = name; var token = jwt.sign(data, jwtSecret, { expiresIn: time }) return token; } } module.exports = Tokens
react部分
login.tsx
import * as React from 'react' import * as ReactDom from 'react-dom' import {Link, browserHistory} from 'react-router'; import * as axios from 'axios'; export default class Login extends React.Component<any,any>{ constructor(props){ super(props) this.state = { userName : '', password : '', yzNoId : '', hash : Math.random() } } public async sbumit(params : any) : Promise<any>{ let res = await axios.post('http://localhost:3000/login',params); if(res.data.verson){ sessionStorage.setItem('token',res.data.token); browserHistory.push("/home") } } handleUserName(e) : any { this.setState({ userName : e.target.value }) } handlePassword(e) : any { this.setState({ password : e.target.value }) } handleYzId(e) : any { this.setState({ yzNoId : e.target.value }) } setHash() { this.setState({ hash : Math.random() }) } render(){ const { userName, password, yzNoId } = this.state; return( <p> <p className="nav-wrap"> <ul className="nav"> <li><Link to="/home">首页</Link></li> <li><Link to="/imgLoad">上传</Link></li> <li><Link to="/login">登陆</Link></li> </ul> </p> <p className="content"> <p className="login-warp"> <p> <input type="text" className="username" value={userName} onChange={this.handleUserName.bind(this)} placeholder="用户名"/> </p> <p> <input type="text" className="password" value={password} onChange={this.handlePassword.bind(this)} placeholder="密码"/> </p> <p> <input type="text" className="yz" value={yzNoId} onChange={this.handleYzId.bind(this)} placeholder="验证码"/> <img src={"http://localhost:3000/captcha?aaa="+this.state.hash} className="yz-img" onClick={this.setHash.bind(this)} /> </p> <p> <input type="button" className="submit" value="登陆" onClick={this.sbumit.bind(this,{userName:userName,password:password,captcha:yzNoId})} /> </p> </p> </p> </p> ) } }
home.js 获取列表信息
import * as React from 'react' import * as ReactDom from 'react-dom' import {Link, browserHistory} from 'react-router'; import * as axios from 'axios'; class Home extends React.Component<any,any>{ constructor(props){ super(props) this.state = { data : '' } } async getList(): Promise<any>{ let token = sessionStorage.getItem('token'); const config = { // 请求头信息 headers: {'x-access-token': token} } let res = await axios.post('http://localhost:3000/list',{},config); if(!res.data.success){ browserHistory.push('/login'); return; } this.setState({ data : res.data }) } render(){ const { data } = this.state; return( <p> <p className="nav-wrap"> <ul className="nav"> <li><Link to="/home">首页</Link></li> <li><Link to="/imgLoad">上传</Link></li> <li><Link to="/login">登陆</Link></li> </ul> </p> <p className="content"> Home <span onClick={this.getList.bind(this)}>获取数据</span> <p>{ data ? data.result.map( (val,k) => { return <li key = {k}>{val.name}</li> }) : null }</p> </p> </p> ) } } export default Home
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!