HTTP常用认证方式

引言

经常在工作中使用到了各种认证方式,但从未考虑过这些认证方式所属的知识范畴,同时也解释不清楚它们。

曾用到的认证方式(看看是否您也用过,但很难解释清楚他们):

Basic认证(访问API时,浏览器会自动弹出一个对话框去输入用户名/密码)
用户名密码认证(进入站点主页前,需要在登陆页面输入用户名和密码,这种更专业的叫法为表单认证)
openID Connect认证(用于第三方登陆认证,比如微信提供给简书的登录认证)
Kerberos认证(一种用于Hadoop集群的客户端认证)
经过阅读《图解HTTP协议》这一书后,对HTTP认证方式有了进一步的了解。本文旨在简单总结HTTP认证方式。

HTTP中有如下常用认证:
1、Basic认证
2、Digest认证
3、SSL Client认证
4、表单认证

HTTP Basic认证

每次客户端请求都需带上Authorization请求头, 值为"Basic xxx"。xxx为对用户名和密码进行Base64编码后的值。 若客户端是浏览器,则浏览器会提供一个输入用户名和密码的对话框,用户输入用户名和密码后,浏览器会保存用户名和密码,用于构造Authorization值。当关闭浏览器后,用户名和密码将不再保存。

用户名/密码经过Base64加码后,这个Base64码值可以轻易被解码并获得用户名/密码,所以此认证方式并不安全。为了传输安全,需要配合SSL使用。

HTTP另外 Digest认证

Digest认证步骤如下:
第一步:客户端访问Http资源服务器。由于需要Digest认证,服务器返回了两个重要字段nonce(随机数)和realm。

第二步: 客户端构造Authorization请求头,值包含username、realm、nouce、uri和response的字段信息。其中,realm和nouce就是第一步返回的值。nouce只能被服务端使用一次。uri(digest-uri)即Request-URI的值,但考虑到经代理转发后Request-URI的值可能被修改、因此实现会复制一份副本保存在uri内。response也可叫做Request-digest,存放经过MD5运算后的密码字符串,形成响应码。

第三步:服务器验证包含Authorization值的请求,若验证通过则可访问资源。

Digest认证可以防止密码泄露和请求重放,但没办法防假冒。所以安全级别较低。

Digest和Basic认证一样,每次都会发送Authorization请求头,也就相当于重新构造此值。所以两者易用性都较差。

HTTP SSL Client认证

SSL认证安全级别较高,但需要承担证书费用。SSL认证过程中涉及到一些重要的概念,数字证书机构的公钥、证书的私钥和公钥、非对称算法(配合证书的私钥和公钥使用)、对称密钥、对称算法(配合对称密钥使用)。

大致的认证步骤如下:
第一步:客户端请求服务资源,服务器要求客户端出示数字证书。
第二步:客户端发送数字证书
第三步:服务器通过数字证书机构的公钥验证数字证书的合法性,验证通过后取出证书的公钥。
第四步:服务端随机生成一个随机数即为对称密钥,并使用非对称算法和证书公钥加密。这个加密后的字符串,只有发送的客户端能解。
第五步:客服端使用非对称解密算法和证书私钥获取服务端发送的对称密钥。后续客户端和服务端的请求直接基于对称算法和对称密钥。由于只有客户端和服务端有对称密钥,所以后续发送的请求较安全。

SSL可以防泄漏、假冒、重放,所以在Web系统中得到了广泛的应用。

SSL客户端认证在实际中用得不多,因为一来需要在客户端中安装证书(升级麻烦)、二来需要承担证书费用。

HTTP 表单认证

基于表单的认证方式并不存在于HTTP规范。所以实现方式也呈现多样化。表单认证一般都会配合cookie+sessiond的使用,现在绝大多数的Web站点都是使用此认证方式。用户在登录页中填写用户名和密码,服务端认证通过后会将sessionId返回给浏览器端,浏览器会保存sessionId到浏览器的Cookie中。因为Http是无状态的,所以浏览器使用Cookie来保存sessionId。下次客户端发送的请求中会包含sessionId值,服务端发现sessionId存在并认证过则会提供资源访问。

在 Spring Security 6 中使用 JWT(JSON Web Token)进行身份验证是一种无状态的认证方式,广泛应用于现代 Web 应用程序中。该机制通过将用户信息编码到一个加密签名的令牌中,并在每次请求时将其附加到 HTTP 请求头中进行验证[^3]。 ### 常见的 JWT 认证流程 1. **登录请求**: 用户提交用户名和密码进行登录,后端系统验证凭证是否正确。 2. **生成 JWT**: 如果验证成功,服务器使用 `JwtUtil` 类生成一个 JWT,其中通常包含用户标识、角色信息以及过期时间等元数据。 3. **返回 JWT 给客户端**: 服务器将生成的 JWT 返回给客户端,客户端通常会将其存储在本地存储(如 localStorage 或 sessionStorage)中。 4. **携带 JWT 发起后续请求**: 客户端在后续请求中将 JWT 放入请求头的 `Authorization` 字段中,格式为 `Bearer <token>`。 5. **验证 JWT 并构建认证对象**: Spring Security 从请求头中提取 JWT,验证其签名有效性并解析出用户信息。如果验证通过,则创建一个 `UsernamePasswordAuthenticationToken` 实例,并将其放入 `SecurityContext` 中以供后续安全逻辑使用[^1]。 ### 核心组件说明 - **JwtUtil.java**:用于生成、校验和解析 JWT。它通常依赖于 `io.jsonwebtoken` 包实现相关功能。例如: ```java import io.jsonwebtoken.*; import java.util.Date; public class JwtUtil { private static final String SECRET_KEY = "your-secret-key"; private static final long EXPIRATION = 86400000; // 24小时 public static String generateToken(String username) { return Jwts.builder() .setSubject(username) .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)) .signWith(SignatureAlgorithm.HS512, SECRET_KEY) .compact(); } public static String parseToken(String token) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(token) .getBody() .getSubject(); } } ``` - **JwtAuthenticationFilter.java**:这是一个自定义过滤器,继承自 `OncePerRequestFilter`,用于拦截每个请求并处理 JWT 的验证逻辑。示例代码如下: ```java import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class JwtAuthenticationFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = extractToken(request); if (token != null && validateToken(token)) { String username = JwtUtil.parseToken(token); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>()); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } private String extractToken(HttpServletRequest request) { String bearerToken = request.getHeader("Authorization"); if (bearerToken != null && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } private boolean validateToken(String token) { try { JwtUtil.parseToken(token); return true; } catch (JwtException e) { return false; } } } ``` - **SecurityConfig.java**:配置类用于注册 JWT 过滤器并设置安全策略。例如: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtAuthenticationFilter jwtAuthenticationFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` ### 相关问题 1. 如何在 Spring Security 6 中实现基于 JWT 的动态权限控制? 2. 在 JWT 认证过程中如何处理令牌过期和刷新机制? 3. 如何在 Spring Boot 项目中集成 Spring Security 和 JWT? 4. 如何测试 Spring Security 6 与 JWT 集成后的认证和授权功能? 5. 如何处理 JWT 签名无效或篡改的情况?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值