springcloud微服务基于redis集群的单点登录

springcloud微服务基于redis集群的单点登录

yls
2019-9-23


简介

本文介绍微服务架构中如何实现单点登录功能
创建三个服务:

  1. 操作redis集群的服务,用于多个服务之间共享数据
  2. 统一认证中心服务,用于整个系统的统一登录认证
  3. 服务消费者,用于测试单点登录

大体思路:每个服务都设置一个拦截器检查cookie中是否有token,若有token,则放行,若没有token,重定向到统一认证中心服务进行登录,登录成功后返回到被拦截的服务。

搭建redis集群服务

搭建redis集群参考文档

搭建统一认证中心

  • 主函数添加注解

    /**

    • 单点登录既要注册到服务注册中心,又要向redis服务系统获取鼓舞
    • 所以要添加 @EnableDiscoveryClient @EnableEurekaClient 两个注解

    */

    @EnableDiscoveryClient @EnableEurekaClient @EnableFeignClients @MapperScan(basePackages = "com.example.itokenservicesso.mapper") @SpringBootApplication public class ItokenServiceSsoApplication {

    1public static void main(String[] args) { 2 SpringApplication.run(ItokenServiceSsoApplication.class, args); 3}

    }

  • 消费redis服务和熔断器

    @FeignClient(value = "itoken-service-redis", fallback = RedisServiceFallBack.class) public interface RedisService {

    1@PostMapping(value = "put") 2public String put(@RequestParam(value = "key") String key, @RequestParam(value = "value") String value, @RequestParam(value = "seconds") long seconds); 3 4@GetMapping(value = "get") 5public String get(@RequestParam(value = "key") String key);

    }

    @Component public class RedisServiceFallBack implements RedisService { @Override public String put(String key, String value, long seconds) { return FallBack.badGateWay(); }

    1@Override 2public String get(String key) { 3 return FallBack.badGateWay(); 4}

    }

    public class FallBack {

    1public static String badGateWay(){ 2 try { 3 return JsonUtil.objectToString(ResultUtil.error(502,"内部错误")); 4 } catch (JsonProcessingException e) { 5 e.printStackTrace(); 6 } 7 return null; 8}

    }

  • 登录服务

    @Service public class LoginServiceImpl implements LoginService {

    1@Autowired 2private UserMapper userMapper; 3 4@Autowired 5private RedisService redisService; 6 7@Override 8public User login(String loginCode, String plantPassword) { 9 //从缓存中获取登录用户的数据 10 String json = redisService.get(loginCode); 11 12 User user = null; 13 //如果缓存中没有数据,从数据库取数据 14 if (json == null) { 15 user = userMapper.selectAll(loginCode); 16 String passwordMd5 = DigestUtils.md5DigestAsHex(plantPassword.getBytes()); 17 if (user != null && passwordMd5.equals(user.getPassword())) { 18 //登录成功,刷新缓存 19 try { 20 redisService.put(loginCode, JsonUtil.objectToString(user), 60 * 60 * 24); 21 } catch (JsonProcessingException e) { 22 e.printStackTrace(); 23 } 24 return user; 25 } else { 26 return null; 27 } 28 } 29 //如果缓存中有数据 30 else { 31 try { 32 user = JsonUtil.stringToObject(json, User.class); 33 } catch (IOException e) { 34 e.printStackTrace(); 35 } 36 } 37 return user; 38}

    }

  • contoller层,处理登录业务和登录跳转

    • 登录业务

      1 /** 2 * 登录业务 3 * 4 * @param loginCode 5 * @param password 6 * @return 7 */ 8 @PostMapping("login") 9 public String login(String loginCode, 10 String password, 11 @RequestParam(required = false) String url, 12 HttpServletRequest request, 13 HttpServletResponse response, 14 RedirectAttributes redirectAttributes) { 15 User user = loginService.login(loginCode, password); 16 //登录成功 17 if (user != null) { 18 19 String token = UUID.randomUUID().toString(); 20 //将token放入缓存 21 String result = redisService.put(token, loginCode, 60 * 60 * 24); 22 //如果redisService没有熔断,也就是返回ok,才能执行 23 if (result != null && result.equals("ok")) { 24 CookieUtil.setCookie(response, "token", token, 60 * 60 * 24); 25 if (url != null && !url.trim().equals("")) 26 return "redirect:" + url; 27 } 28 //熔断后返回错误提示 29 else { 30 redirectAttributes.addFlashAttribute("message", "服务器异常"); 31 } 32 33 } 34 //登录失败 35 else { 36 redirectAttributes.addFlashAttribute("message", "用户名或密码错误"); 37 } 38 return "redirect:/login"; 39 }
    • 登录跳转

      1@Autowired 2private LoginService loginService; 3 4@Autowired 5private RedisService redisService; 6 7/** 8* 跳转登录页 9*/ 10@GetMapping("login") 11public String login(HttpServletRequest request, 12 Model model, 13 @RequestParam(required = false) String url 14) { 15 String token = CookieUtil.getCookie(request, "token"); 16 //token不为空可能已登录,从redis获取账号 17 if (token != null && token.trim().length() != 0) { 18 String loginCode = redisService.get(token); 19 //如果账号不为空,从redis获取该账号的个人信息 20 if (loginCode != null && loginCode.trim().length() != 0) { 21 String json = redisService.get(loginCode); 22 if (json != null && json.trim().length() != 0) { 23 try { 24 User user = JsonUtil.stringToObject(json, User.class); 25 26 //已登录 27 if (user != null) { 28 if (url != null && url.trim().length() != 0) { 29 return "redirect:" + url; 30 } 31 } 32 //将登录信息传到登录页 33 model.addAttribute("user", user); 34 35 } catch (IOException e) { 36 e.printStackTrace(); 37 } 38 39 } 40 } 41 } 42 return "login"; 43}
  • 搭建服务消费者:添加一个拦截器,判断token是否为空

    • 拦截器

      public class WebAdminInterceptor implements HandlerInterceptor {

      1@Autowired 2private RedisService redisService; 3 4@Override 5public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { 6 String token = CookieUtil.getCookie(request, "token"); 7 8 //token为空,一定没有登录 9 if (token == null || token.isEmpty()) { 10 response.sendRedirect("http://localhost:8503/login?url=http://localhost:8601/login"); 11 return false; 12 } 13 return true; 14} 15 16@Override 17public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 18 19 HttpSession session = request.getSession(); 20 User user = (User) session.getAttribute("user"); 21 22 //已登陆状态 23 if (user != null) { 24 if (modelAndView != null) { 25 modelAndView.addObject("user", user); 26 27 } 28 } 29 //未登录状态 30 else { 31 String token = CookieUtil.getCookie(request, "token"); 32 if (token != null && !token.isEmpty()) { 33 String loginCode = redisService.get(token); 34 35 if (loginCode != null && !loginCode.isEmpty()) { 36 String json = redisService.get(loginCode); 37 if (json != null && !json.isEmpty()) { 38 //已登录状态,创建局部会话 39 user = JsonUtil.stringToObject(json, User.class); 40 if (modelAndView != null) { 41 modelAndView.addObject("user", user); 42 } 43 request.getSession().setAttribute("user", user); 44 } 45 } 46 } 47 } 48 49 //二次确认是否有用户信息 50 if (user == null) { 51 response.sendRedirect("http://localhost:8503/login?url=http://localhost:8601/login"); 52 53 } 54 55} 56 57@Override 58public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { 59 60}

      }

    • 配置拦截器

      @Configuration public class WebAdminInterceptorConfig implements WebMvcConfigurer {

      1//将拦截器设置为Bean,在拦截其中才能使用@AutoWired注解自动注入 2@Bean 3WebAdminInterceptor webAdminInterceptor() { 4 return new WebAdminInterceptor(); 5} 6 7@Override 8public void addInterceptors(InterceptorRegistry registry) { 9 registry.addInterceptor(webAdminInterceptor()) 10 .addPathPatterns("/**") 11 .excludePathPatterns("/static"); 12}

      }

  • 任意写一个接口,触发拦截器进行测试

    @RequestMapping(value = {"/login"}) public String index(){ return "index"; }

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )