SSO單點登錄之徒手實現篇

1.環境信息

Springboot 2.2.0
thymeleaf

2.CAS Server關鍵代碼

2.1攔截器

public class LoginHandlerInterceptor implements HandlerInterceptor {
    private final Logger logger = LoggerFactory.getLogger(LoginHandlerInterceptor.class);
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        Object userName = session.getAttribute("userInfo");
        //如果session中有數據,說明已登錄,則頒發token重定向到來源服務
        if(userName!=null){
            logger.info("LoginHandlerInterceptor.preHandle get userInfo from session success!");
            String bizServiceUrl = request.getParameter("bizServiceUrl");
            if(bizServiceUrl != null){
                String casTicket = simpleEnAndDeCode((String)userName);
                String redirectUrl = bizServiceUrl+(bizServiceUrl.contains("?")?"&":"?")+"casTicket="+casTicket;
                response.sendRedirect(redirectUrl);
                return true;
            }
            return true;
        }{
        //如果session中沒有用戶數據,則轉移到登錄界面    request.getRequestDispatcher("/loginpage").forward(request,response);
            return true;
        }
    }
}

2.2攔截路徑配置

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //登錄界面loginpage、用戶密碼校驗login、校驗token的路徑放行validate
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/loginpage","/login","/validate")
                .excludePathPatterns("/css/**","/fonts/**","/js/**");;
    }
}

2.3登錄controller

@Controller
public class LoginController {
    private final Logger logger = LoggerFactory.getLogger(LoginController.class);
    // 映射"/"請求
    @RequestMapping({"/","/loginpage"})
    public String loginPage(Model model,@RequestParam("bizServiceUrl") String bizServiceUrl) {
        System.out.println("HomepageController loginpage方法被調用......");
        model.addAttribute("bizServiceUrl", bizServiceUrl);
        // 根據Thymeleaf默認模板,將返回resources/templates/loginpage.html
        return "loginpage";
    }
    //校驗用戶名、密碼
    @PostMapping("/login")
    public String login(Model model, HttpServletRequest request,HttpServletResponse response,@RequestParam("bizServiceUrl") String bizServiceUrl, @RequestParam("loginName") String userName, @RequestParam("password") String password) throws IOException, NoSuchAlgorithmException {
        //TO DO:校驗userName和password
        boolean validate = true;
        if(validate){
            HttpSession session = request.getSession(true);
            session.setAttribute("userInfo",userName);
            logger.info("login success");
            String casTicket = simpleEnAndDeCode(userName);
            String redirectUrl = bizServiceUrl+(bizServiceUrl.contains("?")?"&":"?")+"casTicket="+casTicket;
            response.sendRedirect(redirectUrl);
            model.addAttribute("userName", userName);
            return "homepage";
        }else{
            return "loginpage";
        }
    }
    //校驗用戶名、密碼
    @GetMapping("/validate")
    @ResponseBody
    public String validate(HttpServletRequest request,HttpServletResponse response,@RequestParam("casTicket") String casTicket) throws IOException, NoSuchAlgorithmException {
        //TO DO:校驗casTicket
        String userName = simpleEnAndDeCode(casTicket);
        boolean validate = true;
        if(validate){
            return userName;
        }else{
            return "";
        }
    }
}

3.ServerA關鍵代碼

3.1攔截器

@Component
public class LoginHandlerInterceptor implements HandlerInterceptor {
    private final Logger logger = LoggerFactory.getLogger(LoginHandlerInterceptor.class);
    @Autowired
    private RestTemplate restTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        boolean needLogin = false;
        boolean needValidate = false;
        String ticket = request.getParameter("casTicket");
        Object userInfo = session.getAttribute("userInfo");
        String casServer = "http://local.cas.com:8088";
        String currentServer = "http://local.servera.com:8091";
        String casValidateUrl = casServer+"/validate";
        //session中已經有值,則放行
        if(userInfo!=null){
            return true;
        }else{
            //session中沒值
            if(ticket==null){
                //沒有ticket,則需重新登錄
                response.sendRedirect(casServer+"?bizServiceUrl="+currentServer);
                return true;
            }else{
                //有ticket,則需找CAS Server驗證
                String userName = restTemplate.getForObject(casValidateUrl+"?casTicket="+ticket,String.class);
                if(userName==null || userName.equals("")){
                    //認證失敗,需要重新登錄
                    response.sendRedirect(casServer+"?bizServiceUrl="+currentServer);
                    return false;
                }
                session.setAttribute("userInfo",userName);
                return true;
            }
        }
    }
}

4.補充說明

  • 用戶、密碼校驗存在DB或redis,校驗可自行實現
  • token生成和校驗可採用JWT實現
  • CAS也可直接使用官網提供的WAR包實現,本文僅爲學習之用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章