html cookie登陆,SSO - 使用cookie和session实现单点登录

什么是单点登录

单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的。

cookie+session实现单点登录

之前的文章有记录过使用CAS开源项目来实现单点登录,也有通过JWT来实现单点登录的。本文是通过cookie和session来实现单点登录,参考许雪里的SSO解决方案:许雪里SSO码云地址

本文基于cookie、session、SpringBoot、redis进行,其中redis只是做一个简单的存储功能,因此搭建项目只需搭建一个SpringBoot项目并引入Thymeleaf和SpringDataRedis的依赖即可。

一、服务划分

分为3个服务:1个登录服务器,2个客户端服务器。

/xxl-sso-server 登录服务器 8080 sso.com

/xxl-sso-web-sample-springboot 项目一 8081 client1.com

/xxl-sso-web-sample-springboot 项目二 8083 client2.com

在本地修改host文件,对不同服务进行区分:

6f6a36f8196996d75c06d6cae6f749f9.png

实现核心:三个系统即使域名不一样,想办法给三个系统同步同一个用户的票据。

1、中央认证服务器:sso.com

2、其他系统想要登录,就要去sso.com登录,登录成功跳转回来

3、只要有一个登录,其他都不用登录

4、所有系统可能域名都不一样,但是所有的系统都统一使用一个cookie(保存sso-sessionid)

简易时序图

e2f29ff4965e77583322888124934d41.png

二、项目搭建及实现

①创建一个中央认证服务(http:sso.com:8080)

1、properties配置文件

server.port=8080

# 这里将用户信息存储在Redis中

spring.redis.host=192.168.200.134

spring.redis.port=6379

2、创建一个login.html页面(Thymeleaf模板引擎)

17147e34a2b3afe87e2e1216a20158ed.png

登录页title>

head>

用户名:

密码:

form>

body>

html>

3、创建LoginController来处理认证相关的请求

@Controller

public class LoginController {

// 注入RedisTemplate

@Autowired

private StringRedisTemplate redisTemplate;

/**

* 通过传过来的令牌,获取用户信息

*/

@ResponseBody

@GetMapping("/userInfo")

public String userInfo(@RequestParam("token") String token){

// 从Redis中,通过token获取用户信息

String username = redisTemplate.opsForValue().get(token);

return username;

}

/**

* 登录页面

* @param url 这个URL就是重定向页面,从哪个页面来,最后要回到哪个页面

* @param sso_token Cookie中存储的sso令牌

*/

@GetMapping("/login.html")

public String loginPage(@RequestParam("redirect_url") String url, Model model, @CookieValue(value = "sso_token",required = false) String sso_token){

// 判断Cookie中是否保存了令牌

// 有令牌表明之前已经登录过了,直接回到之前的页面并带上令牌信息

if(!StringUtils.isEmpty(sso_token)){

return "redirect:" + url + "?token=" + sso_token;

}

model.addAttribute("url",url);

return "login";

}

/**

* 处理登录请求

* @param username 账号

* @param password 密码

* @param url 这个URL就是重定向页面,从哪个页面来,最后要回到哪个页面

*/

@PostMapping("/doLogin")

public String doLogin(String username, String password, String url, HttpServletResponse response){

// 这里模拟登录成功,只要账号和密码不为空,即登陆成功

if(!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)){

// 使用UUID创建一个令牌

String uuid = UUID.randomUUID().toString().replace("-","");

// Redis中以令牌为key,用户名为value进行存储

redisTemplate.opsForValue().set(uuid,username);

// 同时将令牌保存到Cookie中

Cookie sso_token = new Cookie("sso_token",uuid);

response.addCookie(sso_token);

// 回到之前的页面并带上令牌信息

return "redirect:" + url + "?token=" + uuid;

}else{

// 登录失败,跳转到登录页面

return "login";

}

}

}

②创建一个客户端服务(client1.com:8081)

1、properties配置文件

server.port=8081

# 中央认证的地址

sso.server.url=http://sso.com:8080/login.html

2、创建一个受保护的资源页面list.html(Thymeleaf模板引擎)

ff711e4938ee51797fd64d75e055ba06.png

员工列表页title>

head>

欢迎:[[${session.loginUser}]]h1>

  • 姓名:[[${emp}]]li>

    ul>

    body>

    html>

    3、创建一个受保护的资源请求处理器(HelloController)

    @Controller

    public class HelloController {

    // 认证中心的地址

    @Value("${sso.server.url}")

    private String ssoServerUrl;

    /**

    * 无需登录即可访问

    */

    @GetMapping("/hello")

    @ResponseBody

    public String hello(){

    return "hello";

    }

    /**

    * 模拟获取员工列表 - 需要登录之后才能获取

    */

    @GetMapping("/employees")

    public String employees(Model model, HttpSession session, @RequestParam(value = "token",required = false) String token){

    // 判断是否带有token

    // 因为认证之后,会跳到这个请求,如果带了token,就说明登录成功了的

    if(!StringUtils.isEmpty(token)){

    // 登录成功,获取用户信息

    // 通过RestTemplate获取,也可以通过Feign客户端

    // 但是如果认证服务器是其他语言(比如PHP)写的,就没办法通过Feign了

    RestTemplate restTemplate = new RestTemplate();

    ResponseEntity forEntity = restTemplate.getForEntity("http://sso.com:8080/userInfo?token=" + token, String.class);

    String body = forEntity.getBody();

    // 将用户信息存入session

    session.setAttribute("loginUser",body);

    }

    // 从session中查询是否有用户登录了

    Object loginUser = session.getAttribute("loginUser");

    if(loginUser == null){

    // 没有登录,跳转到登录服务器进行登录

    // 使用url上的查询参数标识我们自己是哪个页面

    return "redirect:" + ssoServerUrl + "?redirect_url=http://client1.com:8081/employees";

    }else{

    // 登录成功的模拟数据

    List emps = new ArrayList<>();

    emps.add("柳成荫");

    emps.add("九月清晨");

    model.addAttribute("emps",emps);

    return "list";

    }

    }

    }

    ③创建一个客户端服务(client2.com:8083)

    直接复制上面这个服务即可,改一下请求路径、端口即可。

    ④测试

    1、访问受保护的资源(http://client1.com:8081/employees)

    45bb73d387cf4fadc99476483774558d.png

    因为没有登录,跳转到认证中心。

    2、输入账号密码进行登录

    认证成功,直接跳转到资源页,可以看到确实带了一个token

    26a84b33d7f898c33942e306d9307fad.png

    查看Redis中是否保存了数据:

    3a354dfd762ef0ae042f5b372a661cc8.png

    3、去认证中心看Cookie是否保存了一个令牌(http://sso.com:8080/)

    7a3b30f8d5625c75050f4442c27cc8cf.png

    可以看到确实保存了一个名为sso_token的令牌

    4、访问另一个服务的受保护的资源(http://client2.com:8083/boss)

    这个服务就是复制的第一个的服务,只是把请求路径就修改成了boss进行区分,其他都一样。

    edd151b0cde0be6f587e54b91399c013.png

    因为第一个服务登录成功了,第二个服务访问这个资源,这个资源判定没有登录,就去中央认证中心,发现cookie中存储了一个token,说明之前有人登录过,因此直接返回token,表明已经登录过。

    代码流程图

    1、第一个去认证的服务

    0c5c1035b6858e2057ad29f31dd5236f.png

    2、第二个去认证的服务

    588a6c1f696ab288ad983fb2fd079b2c.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值