热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WEB后台基于Token的WEB后台登录认证机制(并讲解其他认证机制以及cookie和session机制)

继续这一个系列,基于Token的WEB后台登录认证机制(并讲解cookie和session机制)。每个后端不得不解决的认证问题。本系列&
 

继续这一个系列,基于Token的WEB后台登录认证机制(并讲解COOKIE和session机制)。每个后端不得不解决的认证问题。

本系列:


(一)J2EE项目系列(三)–Spring Data JPA+Spring+SpringMVC+Maven快速开发(1)项目架构


(二) J2EE项目系列(三)–Spring Data JPA+Spring+SpringMVC+Maven快速开发(2)多个第三方服务端接入之云旺IM


(三) Java-解决实现JPA的hibernate自动建表的编码问题




文章结构:

(1)JWT(一种基于 token 的认证方案)介绍并介绍其他几大认证机制;
(2)COOKIE和session机制;
(3)Token机制相对于COOKIE机制的好处;
(4)JWT的Java实现;



一、JWT(一种基于 token 的认证方案)介绍:


(1)概述:

JWT就是一种Token的编码算法,服务器端负责根据一个密码和算法生成Token,然后发给客户端,客户端只负责后面每次请求都在HTTP header里面带上这个Token,服务器负责验证这个Token是不是合法的,有没有过期等,并可以解析出subject和claim里面的数据。

(2)相关问题:


1.为什么用JWT?

JWT只通过算法实现对Token合法性的验证,不依赖数据库,Memcached的等存储系统,因此可以做到跨服务器验证,只要密钥和算法相同,不同服务器程序生成的Token可以互相验证。

2.JWT Token不需要持久化在任何NoSQL中,不然背离其算法验证的初心


3.在退出登录时怎样实现JWT Token失效呢?

退出登录, 只要客户端端把Token丢弃就可以了,服务器端不需要废弃Token。

4.怎样保持客户端长时间保持登录状态?

服务器端提供刷新Token的接口, 客户端负责按一定的逻辑刷新服务器Token。

5.服务器端是否应该从JWT中取出userid用于业务查询?

REST API是无状态的,意味着服务器端每次请求都是独立的,即不依赖以前请求的结果,因此也不应该依赖JWT token做业务查询, 应该在请求报文中单独加个userid 字段。

为了做用户水平越权的检查,可以在业务层判断传入的userid和从JWT token中解析出的userid是否一致, 有些业务可能会允许查不同用户的数据。



(3)其他几大认证机制:

1.HTTP Basic Auth:

HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth

2.OAuth(开放授权):

是一个开放的授权标准,允许用户让第三方应用访问该用户在某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。

OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容。
在这里插入图片描述

这种基于OAuth的认证机制适用于个人消费者类的互联网产品,如社交类APP等应用,但是不太适合拥有自有认证权限管理的企业应用;

3.COOKIE Auth:

COOKIE认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端的浏览器端创建了一个COOKIE对象;通过客户端带上来COOKIE对象来与服务器端的session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,COOKIE会被删除。但可以通过修改COOKIE 的expire time使COOKIE在一定时间内有效;



二、COOKIE和session机制:


(1)概述:

COOKIE和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道。

Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;

COOKIE是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。

因为HTTP协议是无状态的,即每次用户请求到达服务器时,HTTP服务器并不知道这个用户是谁、是否登录过等。现在的服务器之所以知道我们是否已经登录,是因为服务器在登录时设置了浏览器的COOKIE!Session则是借由COOKIE而实现的更高层的服务器与浏览器之间的会话。

(2)COOKIE实现机制:

COOKIE是由客户端保存的小型文本文件,其内容为一系列的键值对。 COOKIE是由HTTP服务器设置的,保存在浏览器中, 在用户访问其他页面时,会在HTTP请求中附上该服务器之前设置的COOKIE。

COOKIE的传递流程:

1.浏览器向某个URL发起HTTP请求(可以是任何请求,比如GET一个页面、POST一个登录表单等)

2.对应的服务器收到该HTTP请求,并计算应当返回给浏览器的HTTP响应。(HTTP响应包括请求头和请求体两部分)

3.在响应头加入Set-COOKIE字段,它的值是要设置的COOKIE。

4.浏览器收到来自服务器的HTTP响应。

5.浏览器在响应头中发现Set-COOKIE字段,就会将该字段的值保存在内存或者硬盘中。(Set-COOKIE字段的值可以是很多项COOKIE,每一项都可以指定过期时间Expires。 默认的过期时间是用户关闭浏览器时。)

6.浏览器下次给该服务器发送HTTP请求时, 会将服务器设置的COOKIE附加在HTTP请求的头字段COOKIE中。(浏览器可以存储多个域名下的COOKIE,但只发送当前请求的域名曾经指定的COOKIE, 这个域名也可以在Set-COOKIE字段中指定)。)

7.服务器收到这个HTTP请求,发现请求头中有COOKIE字段, 便知道之前就和这个用户打过交道了.

8.过期的COOKIE会被浏览器删除。

总之

服务器通过Set-COOKIE响应头字段来指示浏览器保存COOKIE, 浏览器通过COOKIE请求头字段来告诉服务器之前的状态。 COOKIE中包含若干个键值对,每个键值对可以设置过期时间。

COOKIE 的安全隐患:

COOKIE提供了一种手段使得HTTP请求可以附加当前状态, 现今的网站也是靠COOKIE来标识用户的登录状态的:

1.用户提交用户名和密码的表单,这通常是一个POST HTTP请求。

2.服务器验证用户名与密码,如果合法则返回200(OK)并设置Set-COOKIE为authed=true。

3.浏览器存储该COOKIE。

4.浏览器发送请求时,设置COOKIE字段为authed=true。

5.服务器收到第二次请求,从COOKIE字段得知该用户已经登录。 按照已登录用户的权限来处理此次请求。

问题是什么??风险是什么??

我们知道可以发送HTTP请求的不只是浏览器,很多HTTP客户端软件(包括curl、Node.js)都可以发送任意的HTTP请求,可以设置任何头字段。 假如我们直接设置COOKIE字段为authed=true并发送该HTTP请求, 服务器岂不是被欺骗了?这种攻击非常容易,COOKIE是可以被篡改的!

COOKIE 防篡改机制:

服务器可以为每个COOKIE项生成签名,由于用户篡改COOKIE后无法生成对应的签名, 服务器便可以得知用户对COOKIE进行了篡改。

例子:一个简单的校验过程:

1.在服务器中配置一个不为人知的字符串(我们叫它Secret),比如:x$sfz32。

2.当服务器需要设置COOKIE时(比如authed=false),不仅设置authed的值为false, 在值的后面进一步设置一个签名,最终设置的COOKIE是authed=false|6hTiBl7lVpd1P。

3.签名6hTiBl7lVpd1P是这样生成的:Hash(‘x$sfz32’+‘true’)。 要设置的值与Secret相加再取哈希。

4.用户收到HTTP响应并发现头字段Set-COOKIE: authed=false|6hTiBl7lVpd1P。

5.用户在发送HTTP请求时,篡改了authed值,设置头字段COOKIE: authed=true|???。 因为用户不知道Secret,无法生成签名,只能随便填一个。

6.服务器收到HTTP请求,发现COOKIE: authed=true|???。服务器开始进行校验: Hash(‘true’+‘x$sfz32’),便会发现用户提供的签名不正确。

通过给COOKIE添加签名,使得服务器得以知道COOKIE被篡改。但是!!还是有风险!

因为COOKIE是明文传输的, 只要服务器设置过一次authed=true|xxxx我不就知道true的签名是xxxx了么, 以后就可以用这个签名来欺骗服务器了。因此COOKIE中最好不要放敏感数据。 一般来讲COOKIE中只会放一个Session Id,而Session存储在服务器端。



(3)session的实现机制:

1.概述:

Session 是存储在服务器端的,避免了在客户端COOKIE中存储敏感数据。 Session 可以存储在HTTP服务器的内存中,也可以存在内存数据库(如redis)中, 对于重量级的应用甚至可以存储在数据库中。

例子:存储在redis中的Session为例,考察如何验证用户登录状态的问题。

1.用户提交包含用户名和密码的表单,发送HTTP请求。

2.服务器验证用户发来的用户名密码。

3.如果正确则把当前用户名(通常是用户对象)存储到redis中,并生成它在redis中的ID。

这个ID称为Session ID,通过Session ID可以从Redis中取出对应的用户对象, 敏感数据(比如authed=true)都存储在这个用户对象中。

4.设置COOKIE为sessionId=xxxxxx|checksum并发送HTTP响应, 仍然为每一项COOKIE都设置签名。

5.用户收到HTTP响应后,便看不到任何敏感数据了。在此后的请求中发送该COOKIE给服务器。

6.服务器收到此后的HTTP请求后,发现COOKIE中有SessionID,进行放篡改验证。

7.如果通过了验证,根据该ID从Redis中取出对应的用户对象, 查看该对象的状态并继续执行业务逻辑。

实现上述过程,在Web应用中可以直接获得当前用户。 相当于在HTTP协议之上,通过COOKIE实现了持久的会话。这个会话便称为Session。



三、Token认证机制相对于COOKIE等机制的好处:

1. 支持跨域访问:

COOKIE是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通过HTTP头传输。(垮域访问:两个域名之间不能跨过域名来发送请求或者请求数据)

2.无状态(也称:服务端可扩展行):

Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的COOKIE或本地介质存储状态信息.

3.更适用CDN:

可以通过内容分发网络请求你服务端的所有资料(如:Javascript,HTML,图片等),而你的服务端只要提供API即可.

4.去耦:

不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可.

5.更适用于移动应用:

当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,COOKIE是不被支持的(你需要通过COOKIE容器进行处理),这时采用Token认证机制就会简单得多。

6. CSRF:

因为不再依赖于COOKIE,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。

7.性能:

一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析要费时得多.

8.不需要为登录页面做特殊处理:

如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.

9.基于标准化:

你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby, Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft).



四、JWT的Java实现:

概述:一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。这里我们只使用简单的载荷,并将JSON对象进行base64编码得到token

过程:登录为例子

第一次认证:第一次登录,用户从浏览器输入用户名/密码,提交后到服务器的登录处理的Action层(controller)

Login Action调用认证服务进行用户名密码认证,如果认证通过,Login Action层调用用户信息服务获取用户信息(包括完整的用户信息及对应权限信息);

返回用户信息后,Login Action从配置文件再经过工具类处理获取Token签名生成的秘钥信息,进行Token的生成

生成Token的过程中可以调用第三方的JWT Lib生成签名后的JWT数据;

完成JWT数据签名后,将其设置到COOKIE对象中,并重定向到首页,完成登录过程;

请求认证:

使用:基于Token的认证机制会在每一次请求中都带上完成签名的Token信息,这个Token信息可能在COOKIE中,也可能在HTTP的Authorization头中;

注意:

客户端(APP客户端或浏览器)通过GET或POST请求访问资源(页面或调用API);

认证服务作为一个Middleware HOOK 对请求进行拦截,首先在COOKIE中查找Token信息,如果没有找到,则在HTTP Authorization Head中查找;

如果找到Token信息,则根据配置文件中的签名加密秘钥,调用JWT Lib对Token信息进行解密和解码;

完成解码并验证签名通过后,对Token中的exp、nbf、aud等信息进行验证;

全部通过后,根据获取的用户的角色权限信息,进行对请求的资源的权限逻辑判断;

如果权限逻辑判断通过则通过Response对象返回;否则则返回HTTP 401;

(1)使用JWT的包:maven导入

io.jsonwebtokenjjwt0.6.0

(2)一个生成token的工具类:

public class JavaWebToken {private static Logger log = Logger.getLogger(JavaWebToken.class);private static Key getKeyInstance() {
// return MacProvider.generateKey();//We will sign our JavaWebToken with our ApiKey secretSignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("APP");Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());return signingKey;}public static String createJavaWebToken(Map claims) {return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS256, getKeyInstance()).compact();}public static Map verifyJavaWebToken(String jwt) {try {Map jwtClaims =Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwt).getBody();return jwtClaims;} catch (Exception e) {log.error("json web token verify failed");return null;}}}

(3)一个从request拿去session,并且解密session得到token得到用户id的类

public class AuthUtil {private static Map getClientLoginInfo(HttpServletRequest request) throws Exception {Map r &#61; new HashMap<>();String sessionId &#61; request.getHeader("sessionId");if (sessionId !&#61; null) {r &#61; decodeSession(sessionId);return r;}throw new Exception("session解析错误");}public static Long getUserId(HttpServletRequest request) throws Exception {return Long.valueOf((Integer)getClientLoginInfo(request).get("userId"));}/*** session解密*/public static Map decodeSession(String sessionId) {try {return verifyJavaWebToken(sessionId);} catch (Exception e) {System.err.println("");return null;}}
}

使用例子&#xff1a;

登录的时候把信息放进session&#xff0c;存到map里&#xff0c;再交由JWT得到token保存起来

在这里插入图片描述

//登录&#64;RequestMapping(value &#61; "/login", method &#61; {RequestMethod.GET, RequestMethod.POST}, produces &#61; "text/html;charset&#61;UTF-8")public String login(String account) {User user &#61; userService.login(account);DTO dto &#61; new DTO();if (user &#61;&#61; null) {dto.code &#61; "-1";dto.msg &#61; "Have not registered";} else {//把用户登录信息放进SessionMap loginInfo &#61; new HashMap<>();loginInfo.put("userId", user.getId());String sessionId &#61; JavaWebToken.createJavaWebToken(loginInfo);System.out.println("sessionID"&#43;sessionId);dto.data &#61; sessionId;}return JSON.toJSONString(dto);}

用户登录以后&#xff0c;其他的用户性知道的操作就可以使用token进行了&#xff0c;安全快捷方便&#xff1a;

在这里插入图片描述

//修改昵称&#64;RequestMapping(value &#61; "/updateName", method &#61; {RequestMethod.GET, RequestMethod.POST})public String updateName(HttpServletRequest request, String name) {DTO dto &#61; new DTO();try {//从session拿到token&#xff0c;再解密得到useridLong userId &#61; AuthUtil.getUserId(request);boolean userIsExist &#61; userService.updateName(userId, name);if (userIsExist &#61;&#61; false) {dto.code &#61; "-1";dto.msg &#61; "Have not updateAvatar";}} catch (Exception e) {e.printStackTrace();}return JSON.toJSONString(dto);}

这就是token机制的登录认证功能简单实现了&#xff0c;安全机制等&#xff0c;以后会有博客补充。



源码下载&#xff1a;WEB后台–基于Token的WEB后台登录认证机制&#xff08;并讲解其他认证机制以及COOKIE和session机制&#xff09;


好了&#xff0c;WEB后台–基于Token的WEB后台登录认证机制&#xff08;并讲解其他认证机制以及COOKIE和session机制&#xff09;讲完了。

本博客是这个系列的第四篇&#xff0c;讲的是一个简单的登录机制实现。另外&#xff0c;这个系列还有一些我在外包项目过程中做的优化,虽然核心算法跟安全处理不可以公布&#xff0c;但我会尽快出完给大家&#xff0c;分享经验给大家。欢迎在下面指出错误&#xff0c;共同学习&#xff01;&#xff01;你的点赞是对我最好的支持&#xff01;&#xff01;

更多内容&#xff0c;可以访问JackFrost的博客


推荐阅读
  • 利用Jenkins与SonarQube集成实现高效代码质量检测与优化
    本文探讨了通过在 Jenkins 多分支流水线中集成 SonarQube,实现高效且自动化的代码质量检测与优化方法。该方案不仅提高了开发团队的代码审查效率,还确保了软件项目的持续高质量交付。 ... [详细]
  • 本文详细解析了如何使用 jQuery 实现一个在浏览器地址栏运行的射击游戏。通过源代码分析,展示了关键的 JavaScript 技术和实现方法,并提供了在线演示链接供读者参考。此外,还介绍了如何在 Visual Studio Code 中进行开发和调试,为开发者提供了实用的技巧和建议。 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 本课程详细介绍了如何使用Python Flask框架从零开始构建鱼书应用,涵盖高级编程技巧和实战项目。通过视频教学,学员将学习到Flask的高效用法,包括数据库事务处理和书籍交易模型的实现。特别感谢AI资源网提供的课程下载支持。 ... [详细]
  • 初次接触AJAX是在去年,当时主要是通过手动编写客户端代码来实现,还需处理被请求的页面,过程相当繁琐。尽管之前就听说过AJAX.NET,但一直没有机会深入了解。本文将作为初学者的指南,详细介绍AJAX.NET的基本概念、核心功能及其在实际项目中的应用技巧,帮助读者快速上手并掌握这一强大的开发工具。 ... [详细]
  • HTML5 Web存储技术是许多开发者青睐本地应用程序的重要原因之一,因为它能够实现在客户端本地存储数据。HTML5通过引入Web Storage API,使得Web应用程序能够在浏览器中高效地存储数据,从而提升了应用的性能和用户体验。相较于传统的Cookie机制,Web Storage不仅提供了更大的存储容量,还简化了数据管理和访问的方式。本文将从基础概念、关键技术到实际应用,全面解析HTML5 Web存储技术,帮助读者深入了解其工作原理和应用场景。 ... [详细]
  • 深入浅出解析HTTP协议的核心功能与应用
    前言——协议是指预先设定的通信规则,确保双方能够按照既定标准进行有效沟通,从而实现准确的信息交换。例如,驯兽师通过拍手使动物坐下,这实际上是一种预设的协议。本文将详细探讨HTTP协议的核心功能及其广泛应用,解析其在现代网络通信中的重要作用。 ... [详细]
  • Django项目中配置媒体文件路径的详细步骤与最佳实践
    在Django项目中配置媒体文件路径的详细步骤包括:首先,创建一个新的应用(如 `app02`),然后在 `settings.py` 文件中配置媒体文件的存储路径。具体来说,需要导入 `os` 模块,并使用 `os.path.join` 方法来指定媒体文件的保存目录。此外,建议在开发和生产环境中分别设置不同的媒体文件路径,以确保项目的灵活性和安全性。为了更好地管理和访问媒体文件,还可以在 `urls.py` 中添加相应的URL配置,以便在开发服务器上直接访问这些文件。 ... [详细]
  • Nginx入门指南:从零开始掌握基础配置与优化技巧
    Nginx入门指南:从零开始掌握基础配置与优化技巧 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • Centos下安装memcached+memcached教程
    本文介绍了在Centos下安装memcached和使用memcached的教程,详细解释了memcached的工作原理,包括缓存数据和对象、减少数据库读取次数、提高网站速度等。同时,还对memcached的快速和高效率进行了解释,与传统的文件型数据库相比,memcached作为一个内存型数据库,具有更高的读取速度。 ... [详细]
  • 电信网为不能访问联通服务器的网站_老板说网站慢,我们总结了三大阶段提升性能...
    作者:李平来源:https:www.cnblogs.comleefreemanp3998757.html前言在前一篇随笔《大型网站系统架构的演化》中&# ... [详细]
  • 开发笔记:Memcached高性能内存对象缓存系统
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Memcached高性能内存对象缓存系统相关的知识,希望对你有一定的参考价值。一、Memcached概述 ... [详细]
  • 深入解读代码页与字符集的概念及其实际应用
    许多开发者可能未曾留意到这一问题,但如果您的网站频繁遭遇不明原因的乱码现象,深入了解代码页与字符集的概念及其实际应用将大有裨益。代码页(Codepage),即内码表,是计算机系统中用于映射字符与其编码值的一种机制,不同的代码页支持不同的字符集,正确选择和配置代码页对于确保文本数据的准确显示至关重要。在多语言环境下,合理运用字符集和代码页能够有效避免字符编码冲突,提升用户体验。 ... [详细]
  • PostgreSQL13.1中文手册第 12 章 全文搜 ... [详细]
author-avatar
mobiledu2502906817
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有