自定义实现简道云SAML单点登录

183 阅读2分钟

最近需要将内部系统与简道云做对接,在实现单点登录时参考官方文档时比较繁琐,技术支持人员也说的不够清楚,其实就是参考下面这幅图的调用过程,其中第2,3步都是访问的公司内部系统接口,通过这两次的请求来确认用户身份,进行登录验证。

初看这张图时,没有明白怎么在第三步验证用户的信息,其实就是在第二步请求内部接口时,对请求直接进行重定向,并同时带入用户的信息,然后在第三步接收重定向带来的参数,用此进行登录的校验。

下面是基于Java代码的实现,只需要在controller中新增两个方法即可。


@Slf4j
@Controller
@NoArgsConstructor
@AllArgsConstructor
class SSOController extends BaseController {
    @Autowired
    private SSOConfig ssoConfig;

    @Autowired
    private SSOService ssoService;

    @Autowired
    private IUserService userService;


    /**
     * 第二步
     * 处理重定向请求的控制器方法
     *
     * @param url  重定向的目标 URL
     * @param user 当前发起登录请求的用户名
     * @param req  HttpServletRequest 对象,用于获取请求信息
     * @param resp HttpServletResponse 对象,用于发送响应
     * @throws Exception 如果在处理请求过程中发生异常
     */
    @GetMapping("/api/redirect")
    public void redirect(@RequestParam String url, @RequestParam String user, HttpServletRequest req, HttpServletResponse resp) throws Exception {
        // 获取当前请求的会话对象
        HttpSession session = req.getSession();
        // 将当前发起登录请求的用户名存储在会话中
        session.setAttribute("username", user);
        // 记录日志,打印当前用户名
        log.info(user);
        // 记录日志,打印当前用户的 JSON 字符串表示
        log.info(JSONUtil.toJsonStr(super.getCurrentUser()));
        // 执行重定向操作,将用户重定向到指定的 URL
        resp.sendRedirect(url);
    }

    /**
     * 第三步
     * 处理单点登录认证请求的控制器方法
     *
     * @param request             认证请求参数
     * @param state               认证状态参数
     * @param httpServletResponse HttpServletResponse 对象,用于发送响应
     * @param req                 HttpServletRequest 对象,用于获取请求信息
     * @throws IOException 如果在处理请求过程中发生 I/O 异常
     */
    @GetMapping("/sso")
    void authn(
        @RequestParam(name = "request", defaultValue = "") String request,
        @RequestParam(name = "state", defaultValue = "") String state,
        HttpServletResponse httpServletResponse,
        HttpServletRequest req
    ) throws IOException {
        // 获取当前请求的会话对象
        HttpSession session = req.getSession();
        // 从会话中获取请求用户的信息,如果不存在则默认为 "root"
        Object username = session.getAttribute("username");
        if (username == null) {
            username = "root";
        }
        // 根据用户名查询用户信息
        User user = userService.findByName(String.valueOf(username));
        // 如果用户不存在,抛出异常
        if (user == null) {
            throw new FebsException("该用户名不存在");
        }
        try {
            // 模拟延迟,这里可以根据实际需要进行调整或移除
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // 如果线程被中断,抛出运行时异常
            throw new RuntimeException(e);
        }
        // 根据认证请求和用户的 JdyCode 获取认证响应
        String response = this.ssoService.getResponse(request, user.getJdyCode());
        // 构造重定向 URL,将认证响应和状态参数传递给 ACS 服务器
        httpServletResponse.sendRedirect(
            String.format(
                "%s?response=%s&state=%s&redirect_uri=https://www.jiandaoyun.com/app/xxxxxxxxx/entry/xxxxxxxx",
                this.ssoConfig.getAcs(), response, state
            )
        );
    }


}