集成Github第三方登录组件

申请OAuth APP

    git主页,登录后

    settings->Developer settings->OAuth APP

1.png


    创建自己的OAuth APP,计下自己的client_id和secret。配置首页URL,回调方法

2.jpg



项目登录页面需要跳转

"https://github.com/login/oauth/authorize?client_id=" +key+ "&redirect_uri=" +uri

此处的key是从git上申请的client_id,uri这是在git申请页面配置的callback URL,如果没问题,则该地址会跳转到git登录授权页面。在git页面登录后,会跳转会回调方法,之后就是自己的逻辑处理了


回调方法

public String ouathLoginReturn(HttpServletRequest request,String code,String oauthType)

回调方法中去调用accesstoken的方法

String ajson = HttpUtils.sendPost("https://github.com/login/oauth/access_token", "client_id=" +key+ "&client_secret=" +secret+ "&code=" +code;);

获得accesstoken后,可以去获取用户信息

tjson = HttpUtils.sendGetInHead("https://api.github.com/user", "","Authorization=token "+accessToken);

此接口需要往head里面添加内容

"Authorization=token "+accessToken

不拼接这段会报401错误或400错误


全段代码如下

public String gitLoginReturn(HttpServletRequest request,String code) throws Exception{
    String appKey = gitAppKey;
    String appSecret = gitAppSecret;
    String accessTokenUrl = gitAccessTokenUrl;
    String redirecturi = gitRedirecturi;
    String getInfoUrl = gitGetTokenInfoUrl;
    String userKey = "id";
    long start = System.currentTimeMillis();
    //authorize回调,返回code
    if(code != null && !"".equals(code)){
        //使用code去请求access_token
        String ajson = HttpUtils.sendPost(accessTokenUrl, getToken(appKey, appSecret, redirecturi, code));
        String accessTokenParameter = "";
        String accessToken = "";
        //获取access_token
        String[] jsons = ajson.split("&");
        if(jsons.length > 1) {
            accessToken = jsons[0].split("=")[1];
            accessTokenParameter = "access_token=" + accessToken + "&Authorization=token "+accessToken;
            String username = "";
            String password = "";
            //通过access_token获取微博用户信息
            //access_token需要放在header中,否则报401错误
            String tjson = HttpUtils.sendGetInHead(getInfoUrl, "",accessTokenParameter);
            Map tmap = (Map) JSONObject.parse(tjson);
            if(tmap != null && tmap.get(userKey) != null){
            /*{
                   "id": 1073880622,
                   "login": lori01,
                   "avatar_url": null
             }*/
                Integer uid = (Integer) tmap.get(userKey);
                String uidStr = String.valueOf(uid);
                SysUser quser = new SysUser();
                quser.setGitUid(uidStr);
                Page<SysUser> page = userService.findAllBySpecification(quser, 0);
                if(page != null && page.getContent().size() > 0){
                    quser = page.getContent().get(0);
                    username = quser.getLoginName();
                    password = quser.getPasswd();
                }else{
                    SysUser newuser = new SysUser();
                    String loginName = "git"+uidStr;
                    newuser.setAccessToken(accessToken);
                    newuser.setLoginName(自定义);
                    newuser.setGitUid(uidStr);
                    newuser.setPassword(自定义);
                    newuser.setRealname((String)tmap.get("login"));
                    newuser.setImg((String)tmap.get("avatar_url"));
                    newuser.setPermission(String.valueOf(Constants.GUEST_ROLE_ID));
                    ResponseVo vo = userService.addUser(newuser);
                    username = 自定义用户名;
                    password = 自定义密码;
                }
            }else {
                return "login";
            }
            UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password,false);
            //UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
            Subject subject = SecurityUtils.getSubject();
                    
            try {
                //登录操作
                subject.login(usernamePasswordToken);
                userService.saveSysUserLog(request, System.currentTimeMillis()-start);
                return"redirect:" + USER_HOME_PAGE;
            } catch(Exception e) {
                return "login";
            }
        }
    }
    return "login";
}

HTTP请求方法

public static String sendGetInHead(String url, String param, String header) {
    String result = "";
    BufferedReader in = null;
    try {
        String urlNameString = url + "?" + param;
        URL realUrl = new URL(urlNameString);
        // 打开和URL之间的连接
        URLConnection connection = realUrl.openConnection();
        // 设置通用的请求属性
        connection.setRequestProperty("accept", "*/*");
        connection.setRequestProperty("charset", "utf-8");
        connection.setRequestProperty("connection", "Keep-Alive");
        connection.setRequestProperty("user-agent",
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        if(header != null && !"".equals(header)) {
            String[] headers = header.split("&");
            for(int i = 0; i < headers.length; i ++) {
                String key = headers[i].split("=")[0];
                String value = headers[i].split("=")[1];
                connection.setRequestProperty(key, value);
            }
        }
        // 建立实际的连接
        connection.connect();
        // 获取所有响应头字段
        Map<String, List<String>> map = connection.getHeaderFields();
        // 遍历所有的响应头字段
        for (String key : map.keySet()) {
        Constants.println(key + "--->" + map.get(key));
        }
        // 定义 BufferedReader输入流来读取URL的响应
        in = new BufferedReader(new InputStreamReader(
        connection.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            result += new String(line.getBytes("ISO-8859-1"),"UTF-8");
            //result = new String(result.getBytes("UTF-8"),"GBK"); 锟斤拷
        }
        //result = new String(result.getBytes("ISO-8859-1"),"UTF-8");
    } catch (Exception e) {
        Constants.println("发送GET请求出现异常!" + e);
        e.printStackTrace();
    }
    // 使用finally块来关闭输入流
    finally {
        try {
            if (in != null) {
                in.close();
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }
    return result;
}
/**
 * 向指定 URL 发送POST方法的请求
 * 
 * @param url
 *            发送请求的 URL
 * @param param
 *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
 * @return 所代表远程资源的响应结果
 */
public static String sendPost(String url, String param) {
    PrintWriter out = null;
    BufferedReader in = null;
    String result = "";
    try {
        URL realUrl = new URL(url);
        // 打开和URL之间的连接
        URLConnection conn = realUrl.openConnection();
        // 设置通用的请求属性
        conn.setRequestProperty("accept", "*/*");
        conn.setRequestProperty("charset", "utf-8");
        conn.setRequestProperty("connection", "Keep-Alive");
        conn.setRequestProperty("user-agent",
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        // 发送POST请求必须设置如下两行
        conn.setDoOutput(true);
        conn.setDoInput(true);
        // 获取URLConnection对象对应的输出流
        out = new PrintWriter(conn.getOutputStream());
        // 发送请求参数
        out.print(param);
        // flush输出流的缓冲
        out.flush();
        // 定义BufferedReader输入流来读取URL的响应
        in = new BufferedReader(
        new InputStreamReader(conn.getInputStream()));
        String line;
        while ((line = in.readLine()) != null) {
            result += line;
        }
    } catch (Exception e) {
        Constants.println("发送 POST 请求出现异常!" + e);
        e.printStackTrace();
    }
    // 使用finally块来关闭输出流、输入流
    finally {
        try {
            if (out != null) {
                out.close();
            }
            if (in != null) {
                in.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    return result;
}


至此,即完成git登录的集成。



---------------分割线---------------------------------

编写过程中出现过的异常

当请求user时,token不是放在header时,get会报400错误,post会报401错误,如下

Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: https://api.github.com/user?access_token=0ce8f51a7165c565d6490fb6e0f0978470d51c72
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1838)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1439)
    at sun.net.www.protocol.http.HttpURLConnection.getHeaderFields(HttpURLConnection.java:2952)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getHeaderFields(HttpsURLConnectionImpl.java:283)
    at com.daimeng.util.HttpUtils.sendGetInHead(HttpUtils.java:140)
    ... 93 more
java.io.IOException: Server returned HTTP response code: 401 for URL: https://api.github.com/user
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1838)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1439)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
    at com.daimeng.util.HttpUtils.sendPostInHead(HttpUtils.java:263)
    at com.daimeng.web.login.action.LoginController.gitLoginReturn(LoginController.java:454)
    at com.daimeng.web.login.action.LoginController$$FastClassBySpringCGLIB$$1a0af34a.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:746)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at com.alibaba.druid.support.spring.stat.DruidStatInterceptor.invoke(DruidStatInterceptor.java:72)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at com.daimeng.web.login.action.LoginController$$EnhancerBySpringCGLIB$$f6351b62.gitLoginReturn(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
    at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
    at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
    at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
    at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
    at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
    at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
    at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
    at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
    at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)
    at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
    at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.daimeng.framework.xssfilter.XssFilter.doFilter(XssFilter.java:79)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:155)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:123)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

使用postman请求,提示会准确点

3.png

提示需要把access token方入header中,格式参考git官方文档如下

5.png

header的格式也是尝试了很多次,最终发现是

Authorization: token 9a05423f1bd6b58d71aea4d88c3498d6ed4566bf

这种格式,至此,postman也成功返回

4.png


至此,本地开发基本完成,部署到阿里云服务器后,还是会产生奇怪的问题,比如

java.net.ConnectException: Connection refused

在请求user接口的时候报连接异常,但多试几次后也有成功的,猜测是阿里云服务器对git服务器的联通性不是很好,会拦截git的连接

git账号登录测试成功~~~~
微博的授权登录也是一样,其实更简单,没有header的要求,全部都是URL参数。 其实OAuth2.0的对接方式都一样 1.跳转登录页面 2.第三方登录后返回code 3.通过code查询access token 4.通过access token查询用户信息 5.根据用户编号绑定自己系统的用户或创建新用户
QQ开发者申请失败,好难搞,最近都不打算集成qq登录了~~
{context}