栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

前后端的身份认证

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

前后端的身份认证

前后端的身份认证

Web开发模式

客户端渲染前后端分离

前后端分离的概念前后端分离的优缺点 如何选择 Web 开发模式 身份认证

不同开发模式下的身份认证 Session 认证机制

HTTP 协议

无状态性如何突破 cookie

cookie简介

cookie概念cookie在身份认证中的作用cookie不具有安全性 在 express 中使用 cookie-parser 中间件

1.下载2.配置3.使用 Session

session工作原理在`express`中使用 `express-session` 中间件

1.安装2.配置3.存数据4.读数据5.清空数据 Session局限性 JWT认证机制

JWT相关知识

1.JWT工作原理2.JWT组成部分3.JWT使用方式 在 express 中使用 JWT

1.安装相关包2.导入相关包3.定义 secret 密钥4.登录后生成 token5.将 token 字符串解析为 JSON 对象6. demo 代码报错总结:

Cannot set headers after they are sent to the clientError: algorithms should be set一直报`UnauthorizedError`

Web开发模式 客户端渲染

优点:

前端耗时少。因为服务器端负责动态的生成 HTML 内容,浏览器只需要直接渲染页面即可。尤其是移动端,更加省电

有利于SEO。因为服务端响应是完整的 HTML 页面内容,所以爬虫更容易爬取获得信息,更利于SEO(搜索引擎优化)。

缺点:

占用服务器资源。服务器来完成页面的内容拼接,如果请求太多,会对服务器造成一定的访问压力。不利于前后端分离开发效率低。使用服务端渲染,则无法进行分工合作,尤其对于前端复杂度较高的项目,不利于项目高效开发。 前后端分离 前后端分离的概念

前后端分离的开发模式,依赖Ajax技术的广泛应用。简而言之,前后端分离的Web开发模式,就是后端只负责提供API接口,前端使用Ajax调用接口的开发模式。

前后端分离的优缺点

优点:

开发体验好。前端专注于UI页面的开发,后端专注于api的开发,且前端有更多的选择性。用户体验好。Ajax技术广泛应用,极大的提高了用户的体验,可以轻松的实现页面的局部刷新。减轻了服务器端的渲染压力。

缺点:

不利于SEO。因为完整的页面需要在客户端动态拼接完成,所有爬虫对无法爬取的页面的有效信息。(解决方案:利用Vue ,React 等前端框架的 SSR 技术能够很好的解决。) 如何选择 Web 开发模式

比如企业级的网站,主要功能是展示而没有复杂的交互,并且需要良好的SEO,则这是我们就需要使用服务器端渲染。而类似后台管理项目,交互性比较强,不需要考虑SEO,那么就可以使用前后端分离的开发模式。 身份认证

身份认证指通过一定的手段,完成对用户身份的确认。

不同开发模式下的身份认证

服务端渲染推荐使用Session认证机制前后端分离推荐使用JWT认证机制 Session 认证机制 HTTP 协议 无状态性

HTTP协议的无状态性,指的是客户端的每次HTTP请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保存每次请求的状态。 如何突破

使用 cookie cookie cookie简介 cookie概念

cookie是储存在用户浏览器中一段不超过4KB的字符串。它由一个名称(Name),一个值(Value)和其他几个用于控制cookie有效期,安全性,使用范围的可选属性组成。

不同域名下的cookie各自独立,每当客户端发起请求的时候,会自动把当前域名下的所有未过期的cookie一同发送到服务器。

总结cookie的几大特性:

自动发送域名独立过期时限4KB限制 cookie在身份认证中的作用

客户端在第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的 cookie ,客户端会自动将cookie保存在浏览器中。随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的 cookie ,通过请求头的形式发送给服务器,服务器即可检验客户端身份。 cookie不具有安全性

由于cookie是储存在浏览器中的,而且浏览器也提供了读写cookie的API,因此cookie很容易被伪造,不具有安全性,因此不建议服务器将重要的隐私数据,通过cookie的形式发送给浏览器。

在 express 中使用 cookie-parser 中间件 1.下载
npm install cookie-parser
2.配置
var cookieParser = require('cookie-parser')
3.使用
// 根据是否记住来设置cookie
// 这里只记录邮箱 隐私的信息不宜记录在cookie里
if(req.body.remember === 'on'){
    res.cookie('user' , {
        email: req.body.email,
    },{
        // 设置记住时间为七天
        maxAge: 7*24*60*60*1000
    })
}else{
    // 如果这次没有设置记住 清理 user 的 okie
    res.clearcookie('user')
}
Session session工作原理

在express中使用 express-session 中间件 1.安装

在 Express 项目中,只需要安装 express-session 中间件,即可在项目中使用 Session 认证:

npm install express-session
2.配置

安装完成后,需要通过require来导入,再通过app.use()来注册session中间件:

// 导入
var session = require('express-session')

// 配置 (路由之前)
app.use(session({
    secret: 'myKeyBoard',        //配置加密字符串
    resave: false,			    //固定写法
    saveUninitialized: true		//固定写法
}))
3.存数据

通过req.session来访问和使用session对象:

// 登录成功 通过Session记录登录状态
req.session.user = data
4.读数据

通过req.session.xxx来读数据:

//通过是否登录来渲染首页
router.get('/' , function(req , res, next){
    if(req.session.user){
        User.findOne({
            email: req.session.user.email
        }).then(function(data){
            res.render('index.html' , {
                user: data,
            })
        })
    }else{
        res.render('index.html' , {
            user: null
        })
    }
})
5.清空数据

通过将指定数据设置为null或者使用 req.session.destroy() 函数:

注意: req.session.destroy() 只会清空当前用户的session,每个用户之间的session独立。

// 处理退出请求
router.get('/logout' , function(req , res){
    // 清除登录状态
    req.session.user = null  //将指定数据设置为`null`
    // req.session.destroy() // 或者使用 req.session.destroy() 函数
    // 刷新当前页面
    // a 标签是同步请求 服务端可以重定向
    res.redirect('/')
})

Session局限性

Session认证机制需要配合cookie才能实现。由于cookie默认不支持跨域访问,所以,当涉及到前端跨域请求后端接口的时候,需要做很多额外的配置,才能实现跨域Session认证。此时推荐JWT身份认证。

JWT认证机制 JWT相关知识 1.JWT工作原理


用户的信息通过token字符串的形式,保存在客户端浏览器中。服务器通过还原token字符串的形式来认证用户的身份。

2.JWT组成部分

通常由三部分组成,分别是Header(头部),Payload(有效荷载),Signature(签名)。

Payload是真正的用户信息,是用户信息加密过后生成的字符串。

Header和Signature是安全性相关的部分,只是为了保证Token的安全性。

三者使用英文分隔符.隔开,格式如下:

Header.Payload.Signature
3.JWT使用方式

客户端收到服务器返回的JWT之后,通常将它储存在localStorage或sessionStorage中。

此后,客户端每次与服务器通信,都要带上这个JWT字符串,从而进行身份验证。

推荐的做法是把JWT放在HTTP请求头的Authorization字段中,格式如下:

Authorization: Bearer 
在 express 中使用 JWT 1.安装相关包
npm install jsonwebtoken express-jwt

jsonwebtoken用于生成jwt字符串express-jwt用于将jwt字符串解析还原成json对象 2.导入相关包

const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
3.定义 secret 密钥

为了保证JWT字符串的安全性,防止JWT字符串再网络传输过程中被别人破解,我们需要专门定义一个用于加密和解密的secret密钥。

当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的JWT字符串。当把JWT字符串解密还原成JSON对象的时候,需要使用secret密钥进行解密。

const secretKey = 'mySecretKey'
4.登录后生成 token

jsonwebtoken包提供sign()方法,将用户的信息加密成JWT字符串,响应给客户端:

参数1:用户的信息对象参数2:加密密钥参数3:配置对象,可配置token有效期

app.post('/api/post' , function(req , res){
    console.log(req.body)
    //省略了登录失败的 code ...
    res.send({
        status:200,
        message: '登录成功',
        token:jwt.sign({
            foo: 'bar',
        } , secretKey ,{ 
            //设置token的有效期 
            //'xxs' xx秒
            //'xxh' xx小时
            expiresIn: '30s' 
        })
    })
})
5.将 token 字符串解析为 JSON 对象

expressJWT({secret: secretKey})解析 Token 的中间件.unless({path : [/^/api//]}) 用来指定哪些接口不需要访问权限(可以自己写正则 ,多个放在数组中用逗号隔开)配置好后会将解析出来的数据直接挂载到req.user 属性上

// expressJWT({secret: secretKey})  解析 Token 的中间件
// .unless({path : [/^/api//]})   用来指定哪些接口不需要访问权限(自己写正则)
// 将解析出来的数据直接挂载到 req.user 上
app.use(expressJWT({secret: secretKey , algorithms: ['HS256']}).unless({path : [/^/api//]}))
6. demo 代码

app.js

const express = require('express')
const bodyParser = require('body-parser')
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
const cors = require('cors')


const secretKey = 'mySecretKey'

var app = express()

// 解决跨域
app.use(cors())

//配置解析 post
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

// expressJWT({secret: secretKey})  解析 Token 的中间件
// .unless({path : [/^/api//]})   用来指定哪些接口不需要访问权限(自己写正则)
// 将解析出来的数据直接挂载到 req.user 上
app.use(expressJWT({secret: secretKey , algorithms: ['HS256']}).unless({path : [/^/api//]}))

app.post('/api/login' , function(req , res){
    return res.send({
        status:200,
        message: '登录成功',
        token:jwt.sign({
            foo: 'bar',
        } , secretKey , { expiresIn: '30s' })
    })
})

app.post('/admin' , function(req , res , next){
    console.log(req.user)
    return res.send({
        status:200,
        message: 'token有效',
    })
})

// 配置一个全局错误处理中间件
app.use(function(err, req, res, next){
    // token解析失败导致的错误
    if(err.name === 'UnauthorizedError') {
        return res.status(401).json({
            err_code: 500,
            message: '无效的token'
        })
    }
    // 其他原因导致的错误 
    return res.status(500).json({
        err_code: 500,
        message: err.message
    })
})

app.listen(5000 , function() {
    console.log('Running...')
})

前端 index.js 页面




    
    
    
    document
    


    
    
    


报错总结: Cannot set headers after they are sent to the client

原因:客户端发送一次请求的时候,服务器端给出了多次响应

解决:每次响应后添加return

Error: algorithms should be set

解决:解密加入解密算法algorithms: ['HS256']

app.use(expressJWT({secret: secretKey , algorithms: ['HS256']}).unless({path : [/^/api//]}))
一直报UnauthorizedError

有可能是token字符串设置有效期过短导致解析时发现token已经过期

还有可能是前端页面发送的token格式有误

正确的格式:

//  请求头          空格 token字符串
Authorization: Bearer 

express-jwt源码
该部分源码来自链接.

//  从options中获取token
if (options.getToken && typeof options.getToken === 'function') {
      try {
        token = options.getToken(req);
      } catch (e) {
        return next(e);
      }
//从authorization中获取token
} else if (req.headers && req.headers.authorization) {
      // 根据空格来划分
      var parts = req.headers.authorization.split(' '); 
      if (parts.length == 2) {
        var scheme = parts[0];
        var credentials = parts[1];
        if (/^Bearer$/i.test(scheme)) {
          // 如果前部分是 'Bearer' 则后半部分是token
          token = credentials;           
        } else {
          if (credentialsRequired) {
            return next(new UnauthorizedError('credentials_bad_scheme', { message: 'Format is Authorization: Bearer [token]' }));
          } else {
            return next();
          }
        }
        //如果以上俩种方法都得不到有效的 token 则报错
      } else {
        return next(new UnauthorizedError('credentials_bad_format', { message: 'Format is Authorization: Bearer [token]' }));
      }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/704009.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号