集成Github第三方登录组件
申请OAuth APP
git主页,登录后
settings->Developer settings->OAuth APP
创建自己的OAuth APP,计下自己的client_id和secret。配置首页URL,回调方法
项目登录页面需要跳转
"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请求,提示会准确点
提示需要把access token方入header中,格式参考git官方文档如下
header的格式也是尝试了很多次,最终发现是
Authorization: token 9a05423f1bd6b58d71aea4d88c3498d6ed4566bf
这种格式,至此,postman也成功返回
至此,本地开发基本完成,部署到阿里云服务器后,还是会产生奇怪的问题,比如
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登录了~~ |