SSO && OAuth App

Fri, Oct 1, 2021 3-minute read

SSO 简直要把我搞死了,关键是这个按钮都找不到,以前用的授权方法失效了,现在就重新撸一遍。其实说真的,如果它教程更清楚点,我申请了 organization 都找不到 SSO 按钮在哪。服了,吐槽。

SSO : Single Sign On

在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。这种方式减少了多次登录产生的时间消耗,提升了用户体验,也辅助了用户管理,是目前一种比较流行的身份认证体系。

CAS:Central Authentication Service 中心认证服务

用 CAS 框架实现多个不同站点的单点登录的原理的关键就是使用一个认证服务器集中处理登陆的事务。是一个企业级的单点登录解决方案,在部署上面,CAS 分为 CAS Server 和 CAS Client 其中 CAS Server 需要独立部署,CAS Client 是 CAS 本身一种 C/S 架构,可认为每个接入的 Web 应用都是 CAS 的 Client,CAS 支持的客户端也比较多,包括 Java,.Net,PHP,Perl,Apache,Ruby 等等。

IAM:Identity and Access Management 身份识别与访问管理

目前一般指统一的身份认证平台,集中管理企业员工和资产的身份和认证管理。

auth2

  • authorization_code
    • 用户登录授权,拿到 code
    • code 换 token
  • implicit
    • 用户登录授权,拿到 token
  • password
    • 验证客户端, 用户名和密码, 拿 token
  • client-credentials
    • 验证客户端, 直接拿 token (多个用户)

auth2

  • user (资源拥有方 user)
  • 资源方()
  • 资源请求方(client)
  • 授权方 OAuth2

auth2 客户端模拟授权(一般开发中)

authorization_code

1.1 获取授权 code

GET auth

1.2 code 换 token

code 换 token 是因为安全性: client 通往 Authorization Service 提供 Redirect Url 等信息, 验证身份,导回 Redirect URI,带上 Authorization code, 这些都发生在前端,游览器中, 大部分通过页面跳转去传递信息。 公开信息不安全。

用 code 向 Authorization Service 换 token 发生在后端,用 token 向 Resource service 换资料, 通常是 Http Post 请求, secret key 只存在在后端中,相对安全

postman 中设置通过授权码流程获取 token 以及自动刷新 token

先从浏览器上访问输入用户名/密码后得到 code, 拿着 code 到 postman 上通过 request 拿到 token

postman 上可以直接配置

image

postman

Github OAuth 的验证

1. Request a user’s GitHub identity

GET https://github.com/login/oauth/authorize

https://github.com/login/oauth/authorize?client_id=xxxxxxxxxxxxxxxxxx&scope=user,public_repo

网页会跳转到之前注册 oauth applicathion 时的 callback url,并且带有 code 参数

http://localhost:8080/login?code=xxxxxxxxxxxxxxxxxxxx

2. Users are redirected back to your site by GitHub

POST https://github.com/login/oauth/access_token

使用 client_id、client_secret 和 code 这三个参数获取用户的 access_token,即用户身份标识

https://github.com/login/oauth/access_token?client_id=xxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxx&code=xxxxxxxxxxxxxxxxxxx

SSO 技术

github 授权登录功能注册 OAuth App 实现 Social login 第三方登录

OAuth App : Settings ➡ Developer settings ➡ OAuth Apps ➡ New OAuth App

code

授权流程
  • 1. 用户向网站发起登录请求

  • 2. 网站将已注册的 OAuth App 的 client_id 作为参数,get 请求发送到 GitHub

  • 3.首次登录你的网站的用户需要被寻询问是否接受被获取用户信息

  • 4.用户接受请求,GitHub 向你的授权 App 回调地址发送一段过期时间为 10 分钟的 code

  • 5.在过期时间内,需要将 client_id、client_secret、code 作为参数 post 到https://github.com/login/oauth/access_token

  • 6.经过 GitHub 鉴权成功,返回一串 access_token&access_type

  • 7.获取到 access_token,并且将它作为参数访问https://api.github.com/user

  • 8.GitHub 将会返回 Json 格式的用户信息

  • 9.你获取到用户信息,保存用户登录状态,回显到主页

设计流程
controller
+ OAuthController
dao
+ TokenBean
model
+ GitHubUser
provider
+ GithubProvider
DemoApplication
  • 1. 新建 spring boot 项目,勾选 spring web、thymeleaf、Lombok 等

  • 2. 用户点击主页(index.html)的 GitHub 登录

  • 3. GitHub 携带 code 回调本站

  • 4. OAuthController 处理 code 将 client_id,client_secret,code 打包成对象

public class TokenBean {
    private String client_id;
    private String client_secret;
    private String code;
    ...
}
@Controller
public class OAuthController {
    @Autowired
    private GithubProvider githubProvider;

    @Value("${github.client_id}") 
    private String clientId;
     @Value("${github.client_secret}") 
    private String clientSecret;
    
    @GetMapping("/callback") // 在申请github personal token里面的网址上面加了 /callback
    public String getAccessToken(@RequestParam("code") String code, Model model)
        // 封装
        TokenBean tokenBean = new TokenBean();
        tokenBean.setClient_id(clientId);
        tokenBean.setClient_secret(clientSecret);
        tokenBean.setCode(code);

        // 获取access token
        String accessToken = githubProvider.getAccessToken(accessTokenBean);
        // 获取用户信息
        GitHubUser gitHubUser = githubProvider.getGitHubUser(accesToken);
        model.addAttribute("user", gitHubUser);
        return "success";
    
}
  • 5.交给 GitHubProvider 处理 getAccessToken, 用 fastjson 将 accessTokenBean 对象转化 json 格式,使用 OkHttp 把 json 数据 POST 请求到 GitHub access_token 返回一串 access_token

处理后再将 accesstoken 作为发送 GET 请求到 GitHub。 最终拿到用户的信息,完成登录。

public String getToken(TokenBean tokenBean) {
     MediaType mediaType = MediaType.get("application/json; charset=utf-8");
        OkHttpClient client = new OkHttpClient();
        // json格式的 tokenBean
        RequestBody body = RequestBody.create(JSON.toJSONString(accessTokenDTO), mediaType);
        Request request = new Request.Builder()
                .url("https://github.com/login/oauth/access_token")
                .post(body)
                .build();
        try (Response response = client.newCall(request).execute()) {
        	// 从返回结果中提取access_token
            String string = response.body().string();
            String AccessToken = string.split("&")[0].split("=")[1];
            return AccessToken;
        } catch (IOException e) {
        }
        return null;
    }
}

  • 6.用 token 获取用户的信息, OKHttp 再把返回的 json 格式的用户信息, 转化为 GitHubUser 对象
public GitHubUser getGitHubUser(String tokenBean) {

        OkHttpClient client = new OkHttpClient();
        // 以拼接字符串的形式,把token作为参数去Get请求url
        // 官方文档 但是会错误, 显示要头传参
        // Request request = new Request.Builder()
        //         .url("https://github.com/login/oauth/access_token" + accessToken)
        //         .build();
        Request request = new Request.Builder()
                .url("https://github.com/login/oauth/access_token" + accessToken)
                .header("Authorization", "token " + accessToken)
                .build();
        try {
        	// 封装返回用户信息
            Response response = client.newCall(request).execute();
            String string = response.body().string();
            GitHubUser gitHubUser = JSON.parseObject(String, GitHubUser.class);
            return gitHubUser;
        } catch (IOException e) {
        }
        return null;
    }
}

---

#### 感谢参考文章

CSDN 博主[FRed](https://blog.csdn.net/weixin_45906715/article/details/107189541)