本文是[链接]的一个章节,该系列文章将介绍 [链接] 这款 Java 博客系统是如何从无到有的,希望大家能通过它对 Solo 从设计到实现有个直观地了解、能为想参与贡献的人介绍清楚项目,也希望能为给重复发明重新定义博客系统的人做个参考 ️ 社区登录重定向 Solo 是通过黑客派社区账号实现登录验证的,用户登录时重定向到 ..

Solo 登录验证社区账号

本文是《Solo 从设计到实现》的一个章节,该系列文章将介绍 Solo 这款 Java 博客系统是如何从无到有的,希望大家能通过它对 Solo 从设计到实现有个直观地了解、能为想参与贡献的人介绍清楚项目,也希望能为给重复发明重新定义博客系统的人做个参考 ❤️

社区登录重定向

Solo 是通过黑客派社区账号实现登录验证的,用户登录时重定向到社区登录页面,登录完成以后重定向回 Solo。

方法 OAuthProcessor#redirectAuth

/**
 * Redirects to HacPai auth page.
 *
 * @param context the specified context
 */
@RequestProcessing(value = "/login/redirect", method = HttpMethod.GET)
public void redirectAuth(final RequestContext context) {
    String referer = context.param("referer");
    if (StringUtils.isBlank(referer)) {
        referer = Latkes.getServePath();
    }

    String state = RandomStringUtils.randomAlphanumeric(16) + referer;
    STATES.add(state);

    final String loginAuthURL = "https://hacpai.com/login?goto=" + Latkes.getServePath() + "/login/callback";
    final String path = loginAuthURL + "?state=" + URLs.encode(state);
    context.sendRedirect(path);
}

登录后重定向回调

  1. 验证 state 防止重放攻击
  2. 处理 Referer 获取参数以及后续跳转
  3. 根据 Open Id(HacPai User Id)查库,并根据系统状态处理(初始化、添加访客用户等)

方法 OAuthProcessor#authCallback

/**
 * OAuth callback.
 *
 * @param context the specified context
 */
@RequestProcessing(value = "/login/callback", method = HttpMethod.GET)
public synchronized void authCallback(final RequestContext context) {
    String state = context.param("state");
    if (!STATES.contains(state)) {
        context.sendError(400);

        return;
    }
    STATES.remove(state);
    String referer = URLs.decode(state);
    referer = StringUtils.substring(referer, 16);

    final Response response = context.getResponse();
    final Request request = context.getRequest();
    final String openId = context.param("userId");
    final String userName = context.param(User.USER_NAME);
    final String userAvatar = context.param("avatar");

    JSONObject user = userQueryService.getUserByGitHubId(openId);
    if (null == user) {
        if (!initService.isInited()) {
            final JSONObject initReq = new JSONObject();
            initReq.put(User.USER_NAME, userName);
            initReq.put(UserExt.USER_AVATAR, userAvatar);
            initReq.put(UserExt.USER_B3_KEY, userName);
            initReq.put(UserExt.USER_GITHUB_ID, openId);
            initService.init(initReq);
        } else {
            user = userQueryService.getUserByName(userName);
            if (null == user) {
                final JSONObject addUserReq = new JSONObject();
                addUserReq.put(User.USER_NAME, userName);
                addUserReq.put(UserExt.USER_AVATAR, userAvatar);
                addUserReq.put(User.USER_ROLE, Role.VISITOR_ROLE);
                addUserReq.put(UserExt.USER_GITHUB_ID, openId);
                addUserReq.put(UserExt.USER_B3_KEY, userName);
                try {
                    userMgmtService.addUser(addUserReq);
                } catch (final Exception e) {
                    LOGGER.log(Level.ERROR, "Registers via oauth failed", e);
                    context.sendError(500);

                    return;
                }
            } else {
                user.put(UserExt.USER_GITHUB_ID, openId);
                user.put(User.USER_NAME, userName);
                user.put(UserExt.USER_AVATAR, userAvatar);
                try {
                    userMgmtService.updateUser(user);
                } catch (final Exception e) {
                    LOGGER.log(Level.ERROR, "Updates user GitHub id failed", e);
                    context.sendError(500);

                    return;
                }
            }
        }
    } else {
        user.put(User.USER_NAME, userName);
        user.put(UserExt.USER_AVATAR, userAvatar);
        try {
            userMgmtService.updateUser(user);
        } catch (final Exception e) {
            LOGGER.log(Level.ERROR, "Updates user name failed", e);
            context.sendError(500);

            return;
        }
    }

    user = userQueryService.getUserByName(userName);
    if (null == user) {
        LOGGER.log(Level.WARN, "Can't get user by name [" + userName + "]");
        context.sendError(404);

        return;
    }

    Solos.login(user, response);
    context.sendRedirect(referer);
    LOGGER.log(Level.INFO, "Logged in [name={0}, remoteAddr={1}] with oauth", userName, Requests.getRemoteAddr(request));
}

关于 GitHub Id

以前的版本是使用 GitHub OAuth 登录的,后来切换为社区登录了。但是数据库字段还有实现方面没有做迁移,依然保留 GitHub Id 命名,现在这个字段存储的是黑客派用户 id。


回到全文目录:《Solo 从设计到实现》

  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。

    Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!
    具体细节请浏览 B3log 构思

    1005 引用 • 7689 回帖 • 650 关注
  • 设计
    93 引用 • 619 回帖 • 1 关注
  • 文档
    51 引用 • 1115 回帖 • 1 关注
1 操作
88250 在 2020-01-14 09:21:42 更新了该帖
22 回帖
请输入回帖内容...
  • WOLFCHAN

    不明觉厉,大佬加油 😄

  • EvilCodes

    涛哥对技术是完全的开放啊,没有一点私心

    2 回复
  • 88250

    谁是涛哥 😂

    1 回复
  • EvilCodes

    打错字了

    1 回复
  • 88250

    社区的回帖内容可以编辑更新的。

  • rainningLovexiang

    目标是成为像大佬您一样的人物

  • ellenbboe

    image.png
    不知道写的对不对 -.-

    1 回复
  • 88250

    有心了,差不多就是这个意思吧 😊

  • xiaoyao2102

    请问现在只能用 GitHub 登录了么?

    1 回复
  • 88250

    是的呢。

    1 回复
  • xiaoyao2102

    不是特别喜欢自己 GitHub 的账号名哈哈。。能换一个最好呢

    1 回复
  • 88250

    GitHub 可以改名的,改好以后社区这边私信我你的新用户名。博客端需要你自己手动修改数据库。

  • Liushaowu

    大佬 请问想使用除了 GitHub 以外的其他第三方登录 怎么办?

    1 回复
  • 88250

    改代码 🤣

    1 回复
  • Liushaowu

    好的,大佬。先把大佬的逻辑吃透后 就自己动手 DIY 😂

  • jetablezhu

    我想问个问题,在社区服务器置换映射 token 后,为什么不能一同将用户信息回调给博客端,还得多一步拿 token 去换回用户信息这一步?

    1 回复
  • 88250

    主要考虑到用户信息带在回调 URL 参数上太长也不安全,所以需要用随机凭证从后端再去请求社区获取。

    1 回复
  • jetablezhu

    不明白,参数可以 post 甚至简单加密。其实社区充当的是代理角色,即使非博客端伪造 OAuth 授权请求,社区还是正常接收,然后回调传递映射 token,我拿到这个 token 一样可以再去社区换回用户信息,所以我不认为规避了什么安全问题吧,倒是可以节省一步请求。

    2 回复
  • 88250

    回调的是 GET 请求,安全问题我指的是网络层面,因为 HTTPS 只能保护 body content 不能保护 URL。

  • lizhongyue248

    因为根本不担心你学会 😂 等你学会 D 大又有新的东西了哈哈哈哈

  • 88250

    现在博客端已经更新为社区登录了,登录跳转回调 GET 请求传递用户名、头像等参数,没有多余的动作,确实简单即是好的。

    1 回复
  • jetablezhu

    👍 登录集成在社区了,这样只要社区是登录状态,博客也自动登录,蛮方便的。
    要是能做到双向就更好了,也就是博客登录了,社区也自动登录
    另外我发现个问题,新下载的最新的 solo 代码,但是数据库还是用的原来的,跑起来后发现皮肤被重置了,可是数据库里的配置还是原来正确的皮肤!

请输入回帖内容 ...