松哥给最近连载的 Spring Security 系列也录制了视频教程,感兴趣的小伙伴请戳这里->Spring Boot+Vue+微人事视频教程(Spring Boot 第十章就是 Spring Security)。

HttpBasic 认证有一定的局限性与安全隐患,因此在实际项目中使用并不多,但是,有的时候为了测试方便,开启 HttpBasic 认证能方便很多。

因此松哥今天还是来和大家简单聊一聊 Spring Security 中的 HttpBasic 认证。

本文是 Spring Security 系列第 29 篇,阅读前面文章有助于更好理解本文:

  1. 挖一个大坑,Spring Security 开搞!
  2. 松哥手把手带你入门 Spring Security,别再问密码怎么解密了
  3. 手把手教你定制 Spring Security 中的表单登录
  4. Spring Security 做前后端分离,咱就别做页面跳转了!统统 JSON 交互
  5. Spring Security 中的授权操作原来这么简单
  6. Spring Security 如何将用户数据存入数据库?
  7. Spring Security+Spring Data Jpa 强强联手,安全管理只有更简单!
  8. Spring Boot + Spring Security 实现自动登录功能
  9. Spring Boot 自动登录,安全风险要怎么控制?
  10. 在微服务项目中,Spring Security 比 Shiro 强在哪?
  11. SpringSecurity 自定义认证逻辑的两种方式(高级玩法)
  12. Spring Security 中如何快速查看登录用户 IP 地址等信息?
  13. Spring Security 自动踢掉前一个登录用户,一个配置搞定!
  14. Spring Boot + Vue 前后端分离项目,如何踢掉已登录用户?
  15. Spring Security 自带防火墙!你都不知道自己的系统有多安全!
  16. 什么是会话固定攻击?Spring Boot 中要如何防御会话固定攻击?
  17. 集群化部署,Spring Security 要如何处理 session 共享?
  18. 松哥手把手教你在 SpringBoot 中防御 CSRF 攻击!so easy!
  19. 要学就学透彻!Spring Security 中 CSRF 防御源码解析
  20. Spring Boot 中密码加密的两种姿势!
  21. Spring Security 要怎么学?为什么一定要成体系的学习?
  22. Spring Security 两种资源放行策略,千万别用错了!
  23. 松哥手把手教你入门 Spring Boot + CAS 单点登录
  24. Spring Boot 实现单点登录的第三种方案!
  25. Spring Boot+CAS 单点登录,如何对接数据库?
  26. Spring Boot+CAS 默认登录页面太丑了,怎么办?
  27. 用 Swagger 测试接口,怎么在请求头中携带 Token?
  28. Spring Boot 中三种跨域场景总结

1.什么是 HttpBasic

Http Basic 认证是 Web 服务器和客户端之间进行认证的一种方式,最初是在 HTTP1.0 规范(RFC 1945)中定义,后续的有关安全的信息可以在 HTTP 1.1 规范(RFC 2616)和 HTTP 认证规范(RFC 2617)中找到。

HttpBasic 最大的优势在于使用非常简单,没有复杂的页面交互,只需要在请求头中携带相应的信息就可以认证成功,而且它是一种无状态登录,也就是 session 中并不会记录用户的登录信息。

HttpBasic 最大的问题在于安全性,因为用户名/密码只是简单的通过 Base64 编码之后就开始传送了,很容易被工具嗅探到,进而暴露用户信息。

Spring Security 中既支持基本的 HttpBasic 认证,也支持 Http 摘要认证,Http 摘要认证是在 HttpBasic 认证的基础上,提高了信息安全管理,但是代码复杂度也提高了不少,所以 Http 摘要认证使用并不多。

这里,松哥将和大家分享 Spring Security 中的这两种认证方式。

2.HttpBasic 认证

我们先来看实现,再来分析它的认证流程。

首先创建一个 Spring Boot 项目,引入 Web 和 Spring Security 依赖,如下:


接下来创建一个测试接口:

@RestControllerpublic class HelloController {    @GetMapping("/hello")    public String hello() {        return "hello";    }}

再开启 HttpBasic 认证:

@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        http.authorizeRequests()                .anyRequest().authenticated()                .and()                .httpBasic();    }}

最后再在 application.properties 中配置基本的用户信息,如下:

spring.security.user.password=123spring.security.user.name=javaboy

配置完成后,启动项目,访问 /hello 接口,此时浏览器中会有弹出框,让我们输入用户名/密码信息:


此时我们查看请求响应头,如下:


可以看到,浏览器响应了 401,同时还携带了一个 WWW-Authenticate 响应头,这个是用来描述认证形式的,如果我们使用的是 HttpBasic 认证,默认响应头格式如图所示。

接下来我们输入用户名密码,点击 Sign In 进行登录,登录成功后,就可以成功访问到 /hello 接口了。

我们查看第二次的请求,如下:


大家可以看到,在请求头中,多了一个 Authorization 字段,该字段的值为 Basic amF2YWJveToxMjM=

amF2YWJveToxMjM= 是一个经过 Base64 编码之后的字符串,我们将该字符串解码之后发现,结果如下:

String x = new String(Base64.getDecoder().decode("amF2YWJveToxMjM="), "UTF-8");

解码结果如下:


可以看到,这就是我们的用户名密码信息。用户名/密码只是经过简单的 Base64 编码之后就开始传递了,所以说,这种认证方式比较危险⚠️。

我们再来稍微总结一下 HttpBasic 认证的流程:

  1. 浏览器发出请求,说要访问 /hello 接口。
  2. 服务端返回 401,表示未认证。同时在响应头中携带 WWW-Authenticate 字段来描述认证形式。
  3. 浏览器收到 401 响应之后,弹出对话框,要求用户输入用户名/密码,用户输入完用户名/密码之后,浏览器会将之进行 Base64 编码,编码完成后,发送到服务端。
  4. 服务端对浏览器传来的信息进行解码,并校验,当没问题的时候,给客户端作出响应。

大致的流程就是这样。

3.Http 摘要认证

Http 摘要认证与 HttpBasic 认证基本兼容,但是要复杂很多,这个复杂不仅体现在代码上,也体现在请求过程中。

Http 摘要认证最重要的改进是他不会在网络上发送明文密码。它的整个认证流程是这样的:

  1. 浏览器发出请求,说要访问 /hello 接口。
  2. 服务端返回 401,表示未认证,同时在响应头中携带 WWW-Authenticate 字段来描述认证形式。不同的是,这次服务端会计算出一个随机字符串,一同返回前端,这样可以防止重放攻击(所谓重放攻击就是别人嗅探到你的摘要信息,把摘要当成密码一次次发送服务端,加一个会变化的随机字符串,生成的摘要信息就会变化,就可以防止重放攻击),如下:

同时,服务端返回的字段还有一个 qop,表示保护级别,auth 表示只进行身份验证;auth-int 表示还要校验内容。

nonce 是服务端生成的随机字符串,这是一个经过 Base64 编码的字符串,经过解码我们发现,它是由过期时间和密钥组成的。在以后的请求中 nonce 会原封不动的再发回给服务端。

  1. 客户端选择一个算法,根据该算法计算出密码以及其他数据的摘要,如下:

可以看到,客户端发送到服务端的数据比较多。

  • nonce 就是服务端发来的随机字符串。
  • response 是生成的摘要信息。
  • nc 表示请求此时,可以防止重放攻击。
  • cnonce 表示客户端发送给服务端的随机字符串。
  1. 服务端根据客户端发送来的用户名,可以查询出用户密码,再根据用户密码可以计算出摘要信息,再将摘要信息和客户端发送来的摘要信息进行对比,就能确认用户身份。

这就是整个流程。

一言以蔽之,原本的用户密码被摘要信息代替了,为了安全,摘要信息会根据服务端返回的随机字符串而发生变化,服务端根据用户密码,同样算出密码的摘要信息,再和客户端传来的摘要信息进行对比,没问题的话,用户就算认证成功了。当然,在此基础上还加了一些过期限制、重放攻击防范机制等。

好了,那这个在 Spring Security 代码中该怎么实现呢?

@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        http.authorizeRequests()                .anyRequest().authenticated()                .and()                .csrf()                .disable()                .exceptionHandling()                .authenticationEntryPoint(digestAuthenticationEntryPoint())                .and()                .addFilter(digestAuthenticationFilter());    }

    @Bean    DigestAuthenticationEntryPoint digestAuthenticationEntryPoint() {        DigestAuthenticationEntryPoint entryPoint = new DigestAuthenticationEntryPoint();        entryPoint.setKey("javaboy");        entryPoint.setRealmName("myrealm");        entryPoint.setNonceValiditySeconds(1000);        return entryPoint;    }    @Bean    DigestAuthenticationFilter digestAuthenticationFilter() {        DigestAuthenticationFilter filter = new DigestAuthenticationFilter();        filter.setAuthenticationEntryPoint(digestAuthenticationEntryPoint());        filter.setUserDetailsService(userDetailsService());        return filter;    }

    @Override    @Bean    protected UserDetailsService userDetailsService() {        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();        manager.createUser(User.withUsername("javaboy").password("123").roles("admin").build());        return manager;    }

    @Bean    PasswordEncoder passwordEncoder() {        return NoOpPasswordEncoder.getInstance();    }

}

配置无非就是两方面,一方面是服务端随机字符串的生成,另一方面就是客户端摘要信息的校验。

  1. 首先提供 DigestAuthenticationEntryPoint 的实例,配置服务端随机数生成的一写参数,例如 nonce 有效期(多长时间会变),realm 的名字,以及生成 nonce 时所需要的 key。nonce 的具体生成逻辑在 DigestAuthenticationEntryPoint#commence 方法中:
public void commence(HttpServletRequest request, HttpServletResponse response,  AuthenticationException authException) throws IOException { HttpServletResponse httpResponse = response; long expiryTime = System.currentTimeMillis() + (nonceValiditySeconds * 1000); String signatureValue = DigestAuthUtils.md5Hex(expiryTime + ":" + key); String nonceValue = expiryTime + ":" + signatureValue; String nonceValueBase64 = new String(Base64.getEncoder().encode(nonceValue.getBytes())); String authenticateHeader = "Digest realm=\"" + realmName + "\", "   + "qop=\"auth\", nonce=\"" + nonceValueBase64 + "\""; if (authException instanceof NonceExpiredException) {  authenticateHeader = authenticateHeader + ", stale=\"true\""; } if (logger.isDebugEnabled()) {  logger.debug("WWW-Authenticate header sent to user agent: "    + authenticateHeader); } httpResponse.addHeader("WWW-Authenticate", authenticateHeader); httpResponse.sendError(HttpStatus.UNAUTHORIZED.value(),  HttpStatus.UNAUTHORIZED.getReasonPhrase());}

在这段代码中,首先获取到过期时间,然后给过期时间和 key 一起计算出消息摘要,再将 nonce 和消息摘要共同作为 value,计算出一个 Base64 编码字符,再将该编码字符写回到前端。

  1. 配置 DigestAuthenticationFilter 过滤器,主要用来处理前端请求。过滤器的源码比较长,我这里就不贴出来了,一个核心的思路就是从前端拿到用户请求的摘要信息,服务端也根据一直的信息算出来一个摘要,再根据传过来的摘要信息进行比对,进而确认用户身份。

配置完成后,重启服务端进行测试。

测试效果其实和 HttpBasic 认证是一样的,所有的变化,只是背后的实现有所变化而已,用户体验是一样的。

4.小结

Http 摘要认证的效果虽然比 HttpBasic 安全,但是其实大家看到,整个流程下来解决的安全问题其实还是非常有限。而且代码也麻烦了很多,因此这种认证方式并未广泛流行开来。

Http 认证小伙伴们作为一个了解即可,里边的有一些思想还是挺有意思的,可以激发我们解决其他问题的思路,例如对于重放攻击的的解决办法,我们如果想自己防御重放攻击,就可以参考这里的实现思路。

好啦,小伙伴们如果有收获,记得点个在看鼓励下松哥哦~

今日干货

刚刚发表查看:66666回复:666

公众号后台回复 ssm,免费获取松哥纯手敲的 SSM 框架学习干货。

base64编码 springboot_Spring Boot 中如何实现 HTTP 认证?相关推荐

  1. 编解码:Base64编码在URL中的应用

    项目查询背景:目前项目中,本地文件全部使用UTF-8进行编码,Android网络访问全部采用Base64加密传输,因此考虑Base64和Url编码是否会有冲突,查询的结果是没有冲突,可以直接放在Url ...

  2. php判断base64编码,检测PHP中的base64编码?

    要检测PHP中的base64编码,代码如下- 示例<?php $value_1 = array(); foreach (str_split('az019AZ~~~!@#$%^*()_+|}?&g ...

  3. java 图片转成base64编码_java语言中如何将一个图片转换为base64编码的数据呢?

    摘要: 下文讲述java语言中将图片转换为base64编码的方法分享,如下所示: 例: /* file为图片文件对象 filePath为转换后base64的存储位置 */ public static ...

  4. Spring Boot 中如何实现 HTTP 认证?

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:在滴滴和头条干了 2 年后端开发,太真实-个人原创100W+访问量博客:点击前往,查看更多 HttpBasic ...

  5. 在Spring Boot中实现通用Auth认证的几种方式

    来源 | https://zhenbianshu.github.io/ 文章介绍了spring-boot中实现通用auth的四种方式,包括 传统AOP.拦截器.参数解析器和过滤器,并提供了对应的实例代 ...

  6. .Net Base64编码

    using System; using System.Text; using System.IO; using System.Security; using System.Security.Crypt ...

  7. python base64编码_JS和Python实现AES算法

    1. AES原理 AES算法是典型的对称加密算法,AES原理可以学习这两篇文档: 漫画:什么是AES算法:https://www.toutiao.com/i6783550080784794124/ A ...

  8. ios php tpbase64编码,iOS Base64编码

    一.介绍 Base64编码是一种数据编码方式,目的是让数据符合传输协议的要求.能够将任何二进制数据,转换成只有64 +1("="等号)个字符组成的文本文件. 提示:Base64不是 ...

  9. 密码学基础:Base64编码

    文章概述: 本文目的:写这篇文章的目的主要是整理下密码学中Base64的知识点,并把它们分享出来.并且帮助初探密码学的坛友们一步一步的用C语言将Base64的编码实现出来. 阅读方法:希望大家在浏览完 ...

最新文章

  1. Qt中树形结构显示目录结构
  2. 转:python模块学习 ---- smtplib 邮件发送
  3. 机器学习:一种新的编程范式
  4. linux如何查看系统架构?(查看系统架构命令)(armv7l)
  5. 柳传志给年轻人的建议:比起过日子,更要奔日子
  6. 程序员修神之路--略懂数据库集群读写分离而已
  7. 设计模式记--Observer Pattern观察者模式
  8. TIA protal与SCL从入门到精通(1)——SCL编程入门
  9. android扫雷代码解释,android的扫雷程序.doc
  10. 如何部署局域网即时通讯软件
  11. 计算机excel猪肉价格分析,猪肉价格的统计模型.doc
  12. dw 用html修改文字样式,Dreamweaver中插入文本以及文本格式设置方法?
  13. 经典语录(确实经典)
  14. C++大法:举世闻名之BOOST大法精华浅析(三)内存管理库(小白piao分享)
  15. Excel如何通过年份上的时间差操作求得员工工龄
  16. python爬取百度迁徙动态图_爬取动态图片—以百度图片为例
  17. AOP技术介绍--(.Net中关于AOP的实现)
  18. matplotlib之pyplot模块plot函数基础二(线条外观:格式字符串fmt)
  19. nuke导入序列的方式
  20. 深度学习算法及其应用

热门文章

  1. 传统BI为什么注定会失败?
  2. 递归方法计划销售订单的计划物料成本
  3. SAP 物料XXXXX的强制帐户设置 (输入帐户设置类别) 的问题解决方法
  4. 找钢网王东:3年赚900亿他是怎么做到的?
  5. 如何从SAP中连接其他数据库
  6. SAP PP模块调研问卷
  7. 带你认识SAP反记账
  8. SAP ABAP逻辑数据库
  9. Function实现ALV Table六:页眉页脚
  10. 赢得市值,失去人心,美团觉得划算吗?