基于SpringBoot+Redis的Session共享与单点登录


title: 基于SpringBoot+Redis的Session共享与单点登录
date: 2019-07-23 02:55:52
categories:

  • 架构
    author: mrzhou
    tags:
  • SpringBoot
  • redis
  • session
  • 单点登录

基于SpringBoot+Redis的Session共享与单点登录

前言

使用Redis来实现Session共享,其实网上已经有很多例子了,这是确保在集群部署中最典型的redis使用场景。在SpringBoot项目中,其实可以一行运行代码都不用写,只需要简单添加添加依赖和一行注解就可以实现(当然配置信息还是需要的)。
然后简单地把该项目部署到不同的tomcat下,比如不同的端口(A、B),但项目访问路径是相同的。此时在A中使用set方法,然后在B中使用get方法,就可以发现B中可以获取A中设置的内容。

但如果就把这样的一个项目在多个tomcat中的部署说实现了单点登录,那就不对了。

所谓单点登录是指在不同的项目中,只需要任何一个项目登录了,其他项目不需要登录。

同样是上面的例子,我们把set和get两个方法分别放到两个项目(set、get)中,并且以集群方式把两个项目都部署到服务器A和B中,然后分别访问A服务器的set和B服务器的get,你就会发现完全得不到你想要的结果。

同一项目中的set/get

依赖添加就不说了,直接使用最简单的方式

@SpringBootApplication
@EnableRedisHttpSession
@RestController
public class SessionShareApplication {

	public static void main(String[] args) {
		SpringApplication.run(SessionShareApplication.class, args);
	}

	@Autowired
	HttpSession session;
	@Autowired
	HttpServletRequest req;
	
	@GetMapping("/set")
	public Object set() {
		session.setAttribute("state", "state was setted.");
		Map<String, Object> map = new TreeMap<>();
		map.put("msg", session.getAttribute("state"));
		map.put("serverPort", req.getLocalPort());
		return map;
	}
	@GetMapping("/get")
	public Object get() {
		Map<String, Object> map = new TreeMap<>();
		map.put("msg", session.getAttribute("state"));
		map.put("serverPort", req.getLocalPort());
		return map;
	}
}

将该项目打war包,分别部署在tomcatA(端口8080),tomcatB(端口8081),然后通过tomcatA/set 方法设置session,再使用 tomcatB/get 方法即可获得session的值。但这只是实现了同一项目session的共享。并不是单点登录。

为了验证,我们不仿将set/get方法拆分为两个项目。

拆分set/get为两个项目

  • get项目
@SpringBootApplication
@EnableRedisHttpSession
@RestController
public class SetApplication {

	public static void main(String[] args) {
		SpringApplication.run(SetApplication.class, args);
	}

	@Autowired
	HttpSession session;
	@Autowired
	HttpServletRequest req;
	
	@GetMapping("/")
	public Object set() {
		session.setAttribute("state", "state was setted.");
		Map<String, Object> map = new TreeMap<>();
		map.put("msg", session.getAttribute("state"));
		map.put("serverPort", req.getLocalPort());
		return map;
	}
}

将该项目打包为set.war

  • set项目
@SpringBootApplication
@EnableRedisHttpSession
@RestController
public class GetApplication {

	public static void main(String[] args) {
		SpringApplication.run(GetApplication.class, args);
	}

	@Autowired
	HttpSession session;
	@Autowired
	HttpServletRequest req;
	
	@GetMapping("/")
	public Object get() {
		Map<String, Object> map = new TreeMap<>();
		map.put("msg", session.getAttribute("state"));
		map.put("serverPort", req.getLocalPort());
		return map;
	}
}

将该项目打包为get.war
再分别将set.war,get.war部署在tomcatA和tomcatB,再通过 tomcatA/set 设置session内容, 然后通过 tomcatB/get 就发现无法获得session的值。

问题分析

尽管我们使用的路径都是一样的,但其实是两个项目,与前面的一个项目是完全不同的,问题就在于 session和cookie在默认情况下是与项目路径相关的,在同一个项目的情况下两个方法所需要的cookie依赖的项目路径是相同的,所以获取session的值就没有问题,但在后一种情况下,cookie的路径是分别属于不同的项目的,所以第二个项目就无法获得第一个项目中设置的session内容了。

解决方法

解决方法在springboot项目中其实也非常简单。既然cookie路径发生了变化,那我们让它配置为相同的路径就解决了。
在每个子项目中都添加一个配置类或者直接设置cookie的路径,如果有域名还可以设置域名的限制,比如 set.xxx.comget.xxx.com 这种情况与我们就需要设置cookie的域名为 xxx.com,以确保无法在哪个项目下都能够获取 xxx.com 这个域名下的cookie值。这样就确保能够正常获得共享的session值了。

@Configuration
public class CookieConfig {

	@Bean
	public static DefaultCookieSerializer defaultCookieSerializer() {
		DefaultCookieSerializer serializer = new DefaultCookieSerializer();
		serializer.setCookiePath("/");
		//serializer.setDomainName("xxx.com"); //如果使用域名访问,建议对这一句进行设置	
		return serializer;
	}
}

以上才是正直的redis实现单点登录的正确打开方式。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用SpringBoot框架结合MyBatis实现Session共享单点登录可以借助SpringSessionRedis来实现。 首先,需要配置SpringSession以使用Redis作为存储方式。可以在SpringBoot的配置文件中添加以下配置: ``` spring.session.store-type=redis spring.session.redis.namespace=spring:session spring.redis.host=127.0.0.1 spring.redis.port=6379 ``` 这样配置后,SpringSession会自动将session信息存储到Redis中。 接着,在登录验证成功后,将用户信息存储到Redis中,并将该用户的唯一标识存储到当前Session的属性中,以便后续验证是否登录。例如: ``` @RequestMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session) { // 验证用户名和密码 // ... // 验证通过后,将用户信息存储到Redis中,并设置Session属性 redisTemplate.opsForHash().put("user:" + username, "username", username); session.setAttribute("username", username); return "success"; } ``` 在后续的请求中,可以通过拦截器或过滤器来验证Session是否有效。例如: ``` @Component public class SessionInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate<String, Object> redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); String username = (String) session.getAttribute("username"); if (StringUtils.isEmpty(username)) { response.sendRedirect("/login"); return false; } String storedUsername = (String) redisTemplate.opsForHash().get("user:" + username, "username"); if (!StringUtils.equals(storedUsername, username)) { response.sendRedirect("/login"); return false; } return true; } } ``` 以上代码片段展示了如何通过拦截器验证Session的有效性。首先从当前Session中获取用户名,如果为空则重定向到登录页面。然后从Redis中获取存储的用户名,如果与当前用户名不匹配,则重定向到登录页面。 这样就实现了SpringBoot、MyBatis、SpringSessionRedis共同完成Session共享单点登录的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜜友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值