区别
Redis和JWT都可以用于实现分布式Session,但它们之间的实现方式和应用场景有所不同。
Redis作为一个内存数据库,支持快速存储和读取Session数据,通常用于Session集中管理,实现Session的共享和持久化。Spring Session框架就是基于Redis的Session管理解决方案之一。
通过将Session数据存储在Redis中,就可以在多个服务器之间共享Session数据,实现Session的分布式管理。同时,Redis提供了高效的Session读写、查询、过期和删除等操作,可以帮助我们更好地管理Session数据,有效地减少Session的内存消耗。
而JWT是一种基于Token的身份验证和授权机制,通常用于实现无状态Session,即客户端在每次请求时传递一个Token,服务器根据这个Token进行验证和授权,不需要保存任何Session信息。
JWT通常适用于多个独立的服务之间进行鉴权和授权,不需要共享Session信息的场景。它的实现方式是将用户的身份信息放入Token中,通过签名和验证来保证Token的可靠性。
总结来说,Redis适用于需要共享Session数据的分布式场景,而JWT适用于需要跨服务进行身份验证和授权的场景。根据实际的应用场景,我们可以选择不同的Session管理解决方案。
若没有使用redis存储,默认是以什么形式存在,怎么存储的
如果没有使用Redis存储Session,则Spring会默认使用Servlet容器提供的Session机制进行存储。
在Servlet容器中,Session数据是将其存储在服务器的内存中,也称为内存Session。Servlet容器可以为每个Session对象分配一个唯一的Session ID,并且该Session ID也作为URL重写和Cookie传递参数使用,以便于在服务器和客户端之间进行传递。
当客户端向服务器发送请求时,服务器会根据Session ID查询相应的Session对象,获取其中存储的信息,以实现Session的持久化和共享。
需要注意的是,由于内存Session是存储在服务器内存中的,因此在高并发场景下容易出现内存消耗过大的问题。因此,当应用需要处理大量的并发Session时,建议使用分布式Session存储方案,如Redis等。
为什么JWT比较适合于邮箱激活场景
JWT(JSON Web Token)是一种基于 JSON 的开放标准(RFC 7519),用于在网络上传输声明。通常用于身份验证和授权。JWT 由三部分组成,分别是头部、载荷和签名,其中头部和载荷都是明文的,签名是用于验证身份的密文。
在邮箱激活方面,JWT 是一种更好的选择,因为:
- 独立与前后端的状态管理
JWT 是一种独立于前后端的状态管理方式,可以在后端生成 JWT 并将其发放给前端,前端可以在之后的操作中将 JWT 发送给后端进行验证。由于 JWT 包含全部必要的信息,因此可以避免使用其他技术(例如 Session)时的状态管理问题,使开发更加简单。
- 可以防止 CSRF 攻击
对于使用 Session 进行状态管理的站点,很容易受到 CSRF 攻击,而 JWT 可以使用 CSRF Token 进行保护。
- 可以通过集成OAuth2来实现更高级别的安全性
JWT 可以作为 OAuth2 协议中的一个关键部件,为应用程序提供更高级别的安全性。OAuth2 的授权服务器可以生成 JWT 并将其发放给客户端,客户端可以使用 JWT 进行身份验证和授权。
适合使用JWT的场景:有效期短,只希望被使用一次
比如,用户注册后发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时之内激活),不能被篡改以激活其他可能的账户,一次性的。这种场景就适合使用jwt。
而由于JWT具有一次性的特性。单点登录和会话管理非常不适合用JWT ,如果在服务端部署额外的逻辑存储JWT 的状态,那还不如使用session。基于session有很多成熟的框架可以开箱即用,但是用JWT 还要自己实现逻辑。
因此,使用 JWT 可以更好地实现邮箱激活的安全性、可扩展性和可维护性,这是一种更好的选择。
springboot整合JWT
在 Spring Boot 项目中实现 JWT 的过程可以分为两个步骤,第一步是生成 JWT,在用户登录后将生成的 JWT 发送给客户端;第二步是在客户端请求时,将 JWT 发送给后端,后端对 JWT 进行验证,如果验证通过则说明用户已经登录,否则需要重新登录。
下面是在 Spring Boot 中实现 JWT,以实现登录态储存为例:
- 添加依赖
在 pom.xml
中添加以下依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
- 生成 JWT
在用户登录成功后,可以使用以下代码生成 JWT 并返回给客户端:
// 导入所需的类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
// 生成 JWT 的方法
private String generateJWT(String username) {
// 设置过期时间为一小时
Date expireDate = new Date(System.currentTimeMillis() + 60 * 60 * 1000);
// 使用 JWT 组件生成 JWT
String jwt = Jwts.builder()
.setSubject(username) // Payload 中写入用户名
.setExpiration(expireDate) // 设置过期时间
.signWith(SignatureAlgorithm.HS512, "secret") // 加密方式以及秘钥
.compact();
return jwt; // 返回生成的 JWT
}
- 验证 JWT
在客户端发送请求时,需要将 JWT 发送到后端进行验证,验证代码如下:
// 导入所需的类
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
import org.springframework.web.filter.OncePerRequestFilter;
public class JwtFilter extends OncePerRequestFilter {
private static final String SECRET = "secret"; // JWT 秘钥
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String header = request.getHeader("Authorization"); // 从请求头获取 JWT
if (header == null || !header.startsWith("Bearer ")) { // 判断 JWT 是否存在
// JWT 不存在
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
String token = header.split(" ")[1]; // 获取 JWT Token
try {
Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
// 验证 JWT 是否过期
if (claims.getExpiration().before(new Date())) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
// 将用户信息储存起来,这里以 username 为例
request.setAttribute("username", claims.getSubject());
// 让请求继续传递
filterChain.doFilter(request, response);
} catch (SignatureException e) {
// JWT 不合法
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
}
}
- 储存登录态
在 JWT 身份验证通过后,可以将用户的登录态储存到 Session 中。可以使用以下代码实现:
// 导入所需的类
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
// 在 Spring Boot 中获取当前用户信息的方法
private Authentication getCurrentAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
// 获取当前登录的用户名
private String getCurrentUsername() {
Authentication authentication = getCurrentAuthentication();
return authentication == null ? null : authentication.getName();
}
// 将用户登录信息储存到 Session 中
private void storeUserInformationInSession(HttpServletRequest request) {
String username = getCurrentUsername();
request.getSession(true).setAttribute("username", username);
}
这样,就实现了在 Spring Boot 项目中使用 JWT 的登录态储存功能。需要注意的是,还需要在登录界面添加 JWT 的传递并在拦截器中进行身份验证,以达到整个项目都使用 JWT 进行身份验证的效果。
springboot整合redis
在Spring Boot中,通过整合Spring Session和Redis来实现分布式Session非常简单。具体实现步骤如下:
- 在pom.xml中加入下面的依赖
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
- 在application.properties文件中配置Redis连接参数
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
- 创建一个配置类,用于配置Spring Session和Redis
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800) // Session过期时间为30分钟
public class SessionConfig {
}
- 在Controller中使用Session
@RestController
public class MyController {
@GetMapping("/testSession")
public String testSession(HttpServletRequest request) {
HttpSession session = request.getSession();
session.setAttribute("key", "value");
return "Session已设置";
}
@GetMapping("/getSession")
public String getSession(HttpServletRequest request) {
HttpSession session = request.getSession();
String value = (String) session.getAttribute("key");
return "Session中的值为:" + value;
}
}
以上就是通过Spring Session和Redis实现分布式Session的步骤。注意,在这个例子中,当使用request.getSession()
时,会默认创建一个新的Session或者返回已经存在的Session,而不是使用默认的Cookie-based实现方式。然后,我们可以使用Session中的setAttribute()
和getAttribute()
方法来存储和读取Session中的数据。在这里,通过使用Redis,我们可以确保Session的数据能够被多个服务器共享,这就是分布式Session的作用。
session如何存储在redis中
在Spring Boot中,Spring Session通过使用Redis来存储Session的数据。在Redis中,Session的数据是以Key-Value的形式进行存储,其中Key是一个唯一的Session ID,Value则是Session中包含的所有信息,如Session的创建时间、最后访问时间、Session属性等。具体实现步骤如下:
- 配置Redis连接参数,如下所示:
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
- 将
spring-session-data-redis
包添加到你项目的依赖中,如下所示:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
- 在你的Spring Boot配置文件中通过
@EnableRedisHttpSession
注解来启用Spring Session并设置Session的过期时间(单位:秒),如下所示:
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
public class RedisSessionConfig {
}
- 完成以上配置后,当你使用Session时,Spring会将Session中的数据存储在Redis中,Key为Session ID,Value为Session的所有数据。这样就可以实现仿佛在单个服务器上一样地处理Session,但实际上Session的数据已经存储在了集群中的所有服务器上。
进一步地,你可以使用redis-cli
命令行来检查Redis中存储的Session信息。例如,你可以运行以下命令来检查Redis中所有的Key:
$ redis-cli
127.0.0.1:6379> KEYS *
1) "spring:session:sessions:bde08356-21b5-4795-bf8b-7ccd12d30c19"
可以看到,存在一个spring:session:sessions
前缀的Key,这个前缀是Spring Session框架中默认的Key前缀,用于存储Session ID。你也可以通过命令对Session信息进行存储、获取、更新等操作。