OAuth2.0 社交登录流程(以github账号登录csdn为例)
- csdn 首先向用户请求 github 登录
- 用户点击 github 的登录按钮
- 携带 client_id 跳转到 github 的登录页面,用户输入用户名和密码
- 当在 github 的登录页面输入用户名密码,点击登录按钮后
- 将登录信息提交到了 github 的授权服务器,授权服务器验证用户和密码,如果验证成功
- 将签发 code,根据重定向的 url 返回 csdn
- csdn 拿到返回 code 后,再加 client_id 和 client_secret(csdn 自己的 client_id和client_secret)再次请求授权服务器
- 授权服务器返回 token
- csdn获取到 github 签发的 token,此时 csdn 会携带 token 又一次向 github 发起请求,访问github的资源服务器
- 访问到 github 的资源服务器,并且根据上一步的请求,返回给csdn响应的信息,如用户的github的用户名,头像等
项目中加入 OAuth 2.0 登录功能
-
在 github 中注册一个OAuth 应用,地址
-
填入相应的信息
-
页面中加入如下代码:
<a href="https://github.com/login/oauth/authorize?client_id=填写自己的clientid&response_type=code&redirect_uri=http://www.auth.mall.com/oauth2.0/github/success"> <img src="/static/login/img/github.png" /> <span>GitHub</span> </a>
登录 github 成功后,github 网站会携带 code 跳转到该url http://www.auth.mall.com/oauth2.0/github/success,请根据自己的应用修改该 url 地址
-
oauth2.0/github/success api
@Slf4j @Controller public class OAuth2Controller { @Autowired MemberFeignService memberFeignService; @GetMapping("/oauth2.0/github/success") public String github(@RequestParam("code") String code, HttpSession session) throws Exception { // 1. 根据code换取accessToken Map<String, String> map = new HashMap<>(); map.put("client_id", "在github上创建OAuth应用的id"); map.put("client_secret", "应用的client_secret"); map.put("code", code); Map<String, String> heards = new HashMap<>(); heards.put("accept", "application/json"); // 向github发送请求,换取token String url = "https://github.com/login/oauth/access_token"; ObjectMapper objectMapper = new ObjectMapper(); cn.hutool.http.HttpResponse httpResponse = HttpUtil .createPost(url) .header("Accept", "application/vnd.github.v3+json") .body(objectMapper.writeValueAsString(map)) .execute() .charset("utf-8"); int statusCode = httpResponse.getStatus(); if (statusCode == 200) { // {"access_token":"返回的token","token_type":"bearer","scope":""} GitHubOAuthTokenResult gitHubOAuthResult = JSON.parseObject(httpResponse.body(), GitHubOAuthTokenResult.class); if (!getUserInfo(gitHubOAuthResult, session)) { return "redirect:http://www.auth.mall.com/login.html"; } } else { return "redirect:http://www.auth.mall.com/login.html"; } // 2. 登录成功,跳回首页 return "redirect:http://www.mall.com"; } private boolean getUserInfo(GitHubOAuthTokenResult gitHubOAuthResult, HttpSession session) throws Exception { String url = "https://api.github.com/user"; // 携带 access_token 访问 github 的开发api,如 https://api.github.com/user,获取用户信息 cn.hutool.http.HttpResponse httpResponse = HttpUtil .createGet(url) .header("Accept", "application/vnd.github.v3+json") .header("Authorization", "token " + gitHubOAuthResult.getAccess_token()) .execute() .charset("utf-8"); int status = httpResponse.getStatus(); if (status == 200) { String resultStr = httpResponse.body(); GitHubUserVo gitHubUserVo = JSON.parseObject(resultStr, GitHubUserVo.class); // 1) 当前用户如果是第一次进入,则自动注册(为当前社交用户生成一个会员信息帐号) // 登录或者注册这个社交用户 GitHubUserFeignVo gitHubUserFeignVo = new GitHubUserFeignVo(); BeanUtils.copyProperties(gitHubUserVo, gitHubUserFeignVo); gitHubUserFeignVo.setAccessToken(gitHubOAuthResult.getAccess_token()); gitHubUserFeignVo.setSocialType(SocialType.GITHUB.getValue()); gitHubUserFeignVo.setSocialUid(String.valueOf(gitHubUserVo.getId())); // 将用户信息写入数据库 R r = memberFeignService.githubOauthLogin(gitHubUserFeignVo); if (r.getCode() == 0) { MemberRespVo member = r.getData("data", new TypeReference<MemberRespVo>() {}); log.info("登录成功:用户{}", member.toString()); session.setAttribute(AuthServerConstant.LOGIN_USER, member); return true; } } return false; } }