栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot Oauth2.0认证授权使用 集成第三方账号

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot Oauth2.0认证授权使用 集成第三方账号

前言

 第一次看到oauth2.0的时候说实话心里是迷茫且惧怕的,自己也有下去小小的了解过,对用户信息反复交互的情况自我感觉掌握度很差。但是在真实完整地去接触学习开发一套涉及完整oauth2.0认证流程之后,我对它又有了新的理解。怎么说呢,由浅入深吧。

oauth2.0认证流程介绍

在真正开始开发之前,我们得先了解oauth2.0整体的运行流程,为什么我们要使用这套流程?我们要用这个流程去做什么内容,这些内容应该怎样去实现。

首先,什么是oauth2.0?

这是本人百度找到的图片,看着蛮简单易懂的

简单介绍一下吧,比如说我们自家公司需要集成第三方网站做登录。

那我们就需要在跳转登录页的时候(不管是token过期还是首次访问的跳转)进行重定向的操作,重定向到第三方网站调用那边的约定接口。

在三方网站做了登录操作之后那边会带着授权code根据我们提供的某个回调地址的参数进行重定向,这个回调地址是我们提供的,也就是我们系统的处理地址。

在拿到授权code之后我们再次调用三方的约定接口(获取accessToken的接口需要code参数)拿到accessToken

然后将accessToken作为参数再次请求获取用户id的约定接口

最后用拿到的用户id调用获取用户信息的接口拿到完整的用户信息完成登录。

以上就是oath2.0的整体流程,说实话看起来可能有点绕,没关系我们在实战中深刻了解一下。

实战开发 开发难点

在了解了上面的oauth2.0流程之后我经过自己实际开发的过程总结出了几个初次开发可能会遇到的问题

1.我们如何能实现访问登录页的时候重定向到第三方登录页?

2.拿到一系列授权code或者token之后怎么去调用第三方的接口获取数据?

3.流程走完之后我们拿到第三方用户数据怎样将其作为已登录用户返回给前端让其跳转到首页?

带着这几个问题我们开始项目实战

实际开发

我们首先要实现的就是登录重定向,一般来说,我们的系统都会去判断当前页面的用户是否是已登录或者过没过期,假如不符合需求就会强制跳转到本系统的登录页。我们就需要利用这一点来进行重定向操作。

大家可以试想一下,我前端判断到用户未登录之后不是跳转到本地登录页,而是给后端一个信息,让后端跳转到自定义的页面是不是就能实现这种操作了呢(为什么不能前端直接跳转,问就是安全性问题)

那就得用上拦截器了,后端和前端约定好重定向的跳转拦截。举个例子

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    
    String[] addPathPatterns = {
            "oauth2login
    String[] excludePathPatterns = {
            "/index",
            "/loan
    public String getURLContent(String strUrl, String requestMethod, HashMap headerMap, HashMap bodyMap) throws Exception {
        StringBuilder strUrlBuilder = new StringBuilder(strUrl);
        //遍历bodyMap将参数连接入url
        if (null != bodyMap){
            for (Map.Entry map : bodyMap.entrySet()){
                strUrlBuilder.append(strUrlBuilder.toString().contains("?") ? "&" : "?").append(map.getKey()).append("=").append(map.getValue());
            }
        }
        strUrl = strUrlBuilder.toString();
        // 将url 以 open方法返回的urlConnection  连接强转为HttpURLConnection连接  (标识一个url所引用的远程对象连接)
        // 此时httpConn只是为一个连接对象,待连接中
        URL url = new URL(strUrl);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        //设置请求方法
        httpConn.setRequestMethod(requestMethod);
        httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); //默认
        //遍历headerMap将请求头加入请求
        if (null != headerMap){
            for (Map.Entry map : headerMap.entrySet()){
                httpConn.setRequestProperty(map.getKey(), (String) map.getValue());
            }
        }
        // 建立连接 (请求未开始,直到connection.getInputStream()方法调用时才发起,以上各个参数设置需在此方法之前进行)
        httpConn.connect();
        BufferedReader reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream(), StandardCharsets.UTF_8));
        String line;
        StringBuffer buffer = new StringBuffer();
        //读取返回值存入StringBuffer
        while ((line = reader.readLine()) != null){
            buffer.append(line);
        }
        reader.close();
        httpConn.disconnect();
        //返回String类型
        return buffer.toString();
    }
}

此段代码我就不多做讲解,大家看注释就行了。主要目的就是拿到目标url(接口地址)和拼接的参数,不管是请求头还是请求体的参数都能放到请求里面传递给目标地址。最后以string的形式接收到目标参数返回的数据(一般是字符串类型的json格式)。

有了这个工具类,我们就可以很舒服的进行目标接口调用了!

//获取用户数据
    private void handCallbackEx(HttpServletRequest request, HttpServletResponse response, String url) throws Exception {
        //初始化调用请求参数
        HashMap loginIdHeaderMap = new HashMap<>();
        HashMap tokenBodyMap = new HashMap<>();
        HashMap userBodyMap = new HashMap<>();
        //获取请求地址传入的code
        String code = request.getParameter("code");
        String state = request.getParameter("state");
        SsoUntil ssoUntil = new SsoUntil();
        if (!checkCallBack(code)) {
            String msg = "参数错误. code";
            _logger.error(msg);
            WebUtils.outputResopnse(response, msg);
        }else {
            if ("0".equals(userType)){
                tokenBodyMap.put("client_id",cqClient_idForCompany);
                tokenBodyMap.put("client_secret",cqClient_secretForCompany);
            }else {
                tokenBodyMap.put("client_id",cqClient_idForDept);
                tokenBodyMap.put("client_secret",cqClient_secretForDept);
            }
            tokenBodyMap.put("redirect_uri",this.GetAliasUrl(state)+url);
            tokenBodyMap.put("code",code);
            tokenBodyMap.put("grant_type","authorization_code");
            //根据参数获取到accessToken
            String Token = ssoUntil.getURLContent(("0".equals(userType) ? auth2urlForCompany : auth2urlForDept) + tokenMethod,"POST",null,tokenBodyMap);
            JSONObject jsonObject = JSONObject.parseObject(Token);
            String accessToken = jsonObject.getString("access_token");
            //检查accessToken
            if (checkCallBack(accessToken)){
                loginIdHeaderMap.put("Authorization","Bearer "+accessToken);
                //根据accessToken获取到loginId
                String loginId = ssoUntil.getURLContent(("0".equals(userType) ? auth2urlForCompany : auth2urlForDept) + loginIdMethod, "POST",loginIdHeaderMap,null);
                //检查loginId
                if (checkCallBack(loginId)){
                    userBodyMap.put("access_token",accessToken);
                    userBodyMap.put("loginid",loginId);
                }else {
                    String msg = "参数错误. loginId";
                    _logger.error(msg);
                    WebUtils.outputResopnse(response, msg);
                }
            }else {
                String msg = "参数错误. accessToken";
                _logger.error(msg);
                WebUtils.outputResopnse(response, msg);
            }
            //根据accessToken与loginId获取到用户信息
            String LoginUser = ssoUntil.getURLContent(("0".equals(userType) ? auth2urlForCompany : auth2urlForDept) + getUserIdMethod, "POST",null, userBodyMap);
            //解析用户信息
            JSONObject userObject = JSONObject.parseObject(LoginUser);
            String result = userObject.getString("result");
            JSONObject resultObject = JSONObject.parseObject(result);
            //存储用户信息
            HashMap userMap = new HashMap<>();
            userMap.put("nickName",resultObject.getString("loginid"));
            userMap.put("name",resultObject.getString("displayname"));
            userMap.put("sex",resultObject.getString("sex"));
            userMap.put("email",resultObject.getString("email"));
            userMap.put("Mob1",resultObject.getString("mobile"));
            userMap.put("UniqID",resultObject.getString("userguid"));
            Person person = this.savePerson(userMap, userType);

            LoginResult logInfo = new LoginResult();
            String nextUrl = "";
            try {
                    nextUrl = this.GetAliasUrl(state);
                    logInfo = this._sessions.Login("", "PY", person.getUniqID(), person.getNickName(), person.getName(), "", WebUtils.getRemoteHost(request), 0, null);
            } catch (RuntimeException var9) {
                String msg = "身份验证失败:";
                _logger.error(msg, var9);
                logInfo.setCode(-1);
                logInfo.setMsg(var9.getMessage());
            }

            if (logInfo != null && logInfo.getCode() == 0 && !StringHelper.isNullOrEmpty(nextUrl)) {
                response.sendRedirect(nextUrl);
            } else {
                String msg = "身份验证失败! " + logInfo.getMsg();
                _logger.info(msg);
                msg = this._errTemplate.replace("${Title}", "身份验证失败").replace("${Msg}", logInfo.getMsg());
                WebUtils.outputResopnse(response, msg);
            }
            }
    }

 注意看我们这个handCallbackEx方法在何处调用的,是在最上方那个拦截器处理方法里面,我们第一次重定向之后根据回调地址回来的请求也会被拦截到,并且执行handCallbackEx处理方法。

在这个方法里面我们做了较多事情,首先用首次拿到的code去获取token。。。。。以此类推,最后拿到用户信息之后存储到我们自己的数据库内作为登录用户的信息。最后将登录用户信息存储到页面cookie让前端读取识别之后跳转到首页了。

最后 

因为本人还只是个初登江湖的小实习生,还是个小菜鸡,所以很多地方总结不全面。不足的地方希望大佬多指出。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/868169.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号