Analysis of single sign on implementation of spring cloud microservice based on redis cluster

brief introduction

This paper introduces how to implement single sign on in microservice architecture

Create three services:

General idea: each service is equipped with an interceptor to check whether there is a token in the cookie. If there is a token, it will be released. If there is no token, @ r_ 301_ 2417 @ log in to the unified authentication center service, and return to the intercepted service after successful login.

Build redis cluster service

Reference documents for setting up redis clusters

Build a unified certification center

Add annotation to main function

/**
 * 单点登录既要注册到服务注册中心,又要向redis服务系统获取鼓舞
 * 所以要添加 @EnableDiscoveryClient  @EnableEurekaClient 两个注解
 *
 */
@EnableDiscoveryClient
@EnableEurekaClient
@EnableFeignClients
@MapperScan(basePackages = "com.example.itokenservicesso.mapper")
@SpringBootApplication
public class ItokenServiceSsoApplication {
  public static void main(String[] args) {
    SpringApplication.run(ItokenServiceSsoApplication.class,args);
  }
}

Consumer redis service and fuse

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

  @PostMapping(value = "put")
  public String put(@RequestParam(value = "key") String key,@RequestParam(value = "value") String value,@RequestParam(value = "seconds") long seconds);

  @GetMapping(value = "get")
  public 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();
  }

  @Override
  public String get(String key) {
    return FallBack.badGateWay();
  }
}
public class FallBack {

  public static String badGateWay(){
    try {
      return JsonUtil.objectToString(ResultUtil.error(502,"内部错误"));
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
    return null;
  }
}

Login service

@Service
public class LoginServiceImpl implements LoginService {
  @Autowired
  private UserMapper userMapper;
  @Autowired
  private RedisService redisService;
  @Override
  public User login(String loginCode,String plantPassword) {
    //从缓存中获取登录用户的数据
    String json = redisService.get(loginCode);
    User user = null;
    //如果缓存中没有数据,从数据库取数据
    if (json == null) {
      user = userMapper.selectAll(loginCode);
      String passwordMd5 = DigestUtils.md5DigestAsHex(plantPassword.getBytes());
      if (user != null && passwordMd5.equals(user.getpassword())) {
        //登录成功,刷新缓存
        try {
          redisService.put(loginCode,JsonUtil.objectToString(user),60 * 60 * 24);
        } catch (JsonProcessingException e) {
          e.printStackTrace();
        }
        return user;
      } else {
        return null;
      }
    }
    //如果缓存中有数据
    else {
      try {
        user = JsonUtil.stringToObject(json,User.class);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    return user;
  }
}

The contoller layer handles login services and login jumps

Login service

  /**
  * 登录业务
  *
  * @param loginCode
  * @param password
  * @return
  */
  @PostMapping("login")
  public String login(String loginCode,String password,@RequestParam(required = false) String url,HttpServletRequest request,HttpServletResponse response,RedirectAttributes redirectAttributes) {
    User user = loginService.login(loginCode,password);
    //登录成功
    if (user != null) {

      String token = UUID.randomUUID().toString();
      //将token放入缓存
      String result = redisService.put(token,loginCode,60 * 60 * 24);
      //如果redisService没有熔断,也就是返回ok,才能执行
      if (result != null && result.equals("ok")) {
        CookieUtil.setCookie(response,"token",token,60 * 60 * 24);
        if (url != null && !url.trim().equals(""))
          return "redirect:" + url;
      }
      //熔断后返回错误提示
      else {
        redirectAttributes.addFlashAttribute("message","服务器异常");
      }

    }
    //登录失败
    else {
      redirectAttributes.addFlashAttribute("message","用户名或密码错误");
    }
    return "redirect:/login";
  }

Login jump

  @Autowired
  private LoginService loginService;

  @Autowired
  private RedisService redisService;

  /**
  * 跳转登录页
  */
  @GetMapping("login")
  public String login(HttpServletRequest request,Model model,@RequestParam(required = false) String url
  ) {
    String token = CookieUtil.getCookie(request,"token");
    //token不为空可能已登录,从redis获取账号
    if (token != null && token.trim().length() != 0) {
      String loginCode = redisService.get(token);
      //如果账号不为空,从redis获取该账号的个人信息
      if (loginCode != null && loginCode.trim().length() != 0) {
        String json = redisService.get(loginCode);
        if (json != null && json.trim().length() != 0) {
          try {
            User user = JsonUtil.stringToObject(json,User.class);

            //已登录
            if (user != null) {
              if (url != null && url.trim().length() != 0) {
                return "redirect:" + url;
              }
            }
            //将登录信息传到登录页
            model.addAttribute("user",user);

          } catch (IOException e) {
            e.printStackTrace();
          }

        }
      }
    }
    return "login";
  }

Build a service consumer: add an interceptor to judge whether the token is empty

Interceptor

public class WebAdminInterceptor implements HandlerInterceptor {
  @Autowired
  private RedisService redisService;
  @Override
  public boolean preHandle(HttpServletRequest request,Object handler) throws Exception {
    String token = CookieUtil.getCookie(request,"token");
    //token为空,一定没有登录
    if (token == null || token.isEmpty()) {
      response.sendRedirect("http://localhost:8503/login?url=http://localhost:8601/login");
      return false;
    }
    return true;
  }
  @Override
  public void postHandle(HttpServletRequest request,Object handler,ModelAndView modelAndView) throws Exception {
    HttpSession session = request.getSession();
    User user = (User) session.getAttribute("user");
    //已登陆状态
    if (user != null) {
      if (modelAndView != null) {
        modelAndView.addObject("user",user);
      }
    }
    //未登录状态
    else {
      String token = CookieUtil.getCookie(request,"token");
      if (token != null && !token.isEmpty()) {
        String loginCode = redisService.get(token);

        if (loginCode != null && !loginCode.isEmpty()) {
          String json = redisService.get(loginCode);
          if (json != null && !json.isEmpty()) {
            //已登录状态,创建局部会话
            user = JsonUtil.stringToObject(json,User.class);
            if (modelAndView != null) {
              modelAndView.addObject("user",user);
            }
            request.getSession().setAttribute("user",user);
          }
        }
      }
    }

    //二次确认是否有用户信息
    if (user == null) {
      response.sendRedirect("http://localhost:8503/login?url=http://localhost:8601/login");

    }
  }
  @Override
  public void afterCompletion(HttpServletRequest request,Exception ex) throws Exception {

  }
}

Configuring Interceptors

@Configuration
public class WebAdminInterceptorConfig implements @R_502_320@ {

  //将拦截器设置为Bean,在拦截其中才能使用@AutoWired注解自动注入
  @Bean
  WebAdminInterceptor webAdminInterceptor() {
    return new WebAdminInterceptor();
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(webAdminInterceptor())
        .addPathPatterns("/**")
        .excludePathPatterns("/static");
  }
}

Write an interface arbitrarily and trigger the interceptor for test

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

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>