java 单点登录

单点登录
单点登录的意思就是,我登录一个网站。这个网站包含在别的单点登录里面的系统。我都无需登录、可以直接访问。

想要实现这种效果,原理3点

  1. 我需要把用户信息放到一个全局对象里面,但是每个网站服务器不一样,所以我们应该放到mysql或者redis中,因为用户登录信息这种时效性。所以我们使用redis来作为session对象。

  2. 如果A网站登录了,我们访问B网站的时候,想要实现取到这个用户的信息,总要有个k去redis中取,不然B网站怎么知道是内个用户登录了呢?所以我们需要有个保存在浏览器中的对象。也就是cookie,我A网站登录的时候,我把用户信息放到redis中,我还需要把redis中的key 放到cookie中。这样去访问B网站的时候,我就可以通过浏览器保存的cookie对象直接从redis中查出来。从而实现单点登录。

  3. 我们要明白的事情就是 A ,B网站都是一个服务器,单点登录是另外一个服务器。
    我们登录A或者B网站的时候,都会去判断是否用户登录,如果没有用户登录,我们需要直接通过访问到单点登录服务器,去进行登录操作,登录操作进行完毕,会把用户信息存放到redis中,同时会创建cookie对象。
    然后完成登录后,会跳转到A 或者B网站。此时cookie中有数据,然后A服务器还需要通过cookie里面的key去单点登录服务器中拿到值,然后放到session对象中,登录就结束了。

上代码 服务器有client1(A),client2(B),sso(单点登录)
这块代码 A服务器

A B服务器代码都是一样的,大概流程 先去判断是否有token,第一次登陆指定没有,然后我们就会带着url跳转到单点登陆服务器中。

  /**
     * 需要登录状态访问
     */
    @GetMapping(value = "/employees")
    public String employees(Model model, HttpSession session,
                            @RequestParam(name = "token", required = false) String token) {
        if (!StringUtils.isEmpty(token)) {
            // 根据token去sso认证中心获取用户信息
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> entity = restTemplate.getForEntity("http://sso.com:8080/userinfo?token=" + token, String.class);
            session.setAttribute("loginUser", entity.getBody());
        }
        Object loginUser = session.getAttribute("loginUser");
        if (loginUser == null && token == null) {
            // 未登录,跳转认证服务器登录
            return "redirect:http://sso.com:8080/login.html?redirect_url=http://client1.com:8081/employees";
        } else {
            // 登录状态显示
            List<String> emps = new ArrayList<>();
            emps.add("张三");
            emps.add("李四");
            model.addAttribute("emps", emps);
            return "employees";
        }

    }

这块代码 B服务器

 @GetMapping(value = "/employees")
    public String employees(Model model, HttpSession session,
                            @RequestParam(name = "token", required = false) String token) {
        if (!StringUtils.isEmpty(token)) {
            // 根据token去sso认证中心获取用户信息
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> entity = restTemplate.getForEntity("http://sso.com:8080/userinfo?token=" + token, String.class);
            session.setAttribute("loginUser", entity.getBody());
        }
        Object loginUser = session.getAttribute("loginUser");
        if (loginUser == null && token == null) {
            // 未登录,跳转认证服务器登录
            return "redirect:http://sso.com:8080/login.html?redirect_url=http://client2.com:8082/employees";
        } else {
            // 登录状态显示
            List<String> emps = new ArrayList<>();
            emps.add("张三");
            emps.add("李四");
            model.addAttribute("emps", emps);
            return "employees";
        }

下面是单点登录的代码
接下来的就是核心
我们进入会有两种情况
第一种
通过 @CookieValue(value = “sso_token”, required = false) String token 这个代码去判断。如果cookie里面没有值就说明我们是第一次登录。
首次登录。我们登录后回创建cookie对象和redis存放。
然后登录。

第二种,cookie里面有对象,我们直接带着cookie里面的值,也就是代码中的token。然后返回到当初服务器的方法,重新进行访问,这个时候方法中的token参数就有了值,这样就可以实现A B服务器的单点登录。

@Controller
public class LoginController {

    @Autowired
    StringRedisTemplate redisTemplate;

    @ResponseBody
    @GetMapping("/userinfo")
    public String userInfo(@RequestParam("token") String token) {
        String username = redisTemplate.opsForValue().get(token);
        return username;
    }

    /**
     * 访问登录页
     * @param url       登录成功回调页
     * @param sso_token cookie值
     */
    @GetMapping(value = "/login.html")
    public String login(@RequestParam("redirect_url") String url, Model model,
                        @CookieValue(value = "sso_token", required = false) String token) {
        // 根据token获取用户信息
        if (!StringUtils.isEmpty(token)) {
            String username = redisTemplate.opsForValue().get(token);
            if (!StringUtils.isEmpty(username)) {
                // token正确,已登录状态,跳转回客户端【当前访问客户端共享了其他客户端的登录状态】
                return "redirect:" + url + "?token=" + token;
            }
        }
        // 不存在sso_token,未登录返回登录页,并将回调地址链路下传
        model.addAttribute("url", url);
        return "login";
    }

    /**
     * 登录
     * @param url       登录成功回调页
     */
    @PostMapping(value = "/doLogin")
    public String doLogin(String username, String password, String url,
                          Model model, HttpServletResponse response) {
        if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
            // 登录成功,跳转回调页
            String token = UUID.randomUUID().toString().replace("-", "");
            // token作为key,用户信息作为value存入redis中
            redisTemplate.opsForValue().set(token, username);
            // 在sso.com域名下设置cookie,使得不同客户端访问单点登录时可以带上cookie值成功登录
            Cookie cookie = new Cookie("sso_token", token);
            response.addCookie(cookie);
            return "redirect:" + url + "?token=" + token;
        }
        // 登录失败
        model.addAttribute("url", url);
        return "login";
    }

}

瞎写的 看不懂拉倒

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值