├── pom.xml ├── readme.md └── src └── main ├── java └── org │ └── yangjie │ ├── Application.java │ ├── config │ └── WebMvcConfig.java │ ├── controller │ ├── QQController.java │ └── WeiboController.java │ ├── service │ ├── QQService.java │ └── WeiboService.java │ └── util │ ├── HttpUtil.java │ └── JsonUtil.java ├── resources └── application.yml └── webapp ├── index.html └── my.html /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | org.java.util 6 | java_oauth 7 | 0.0.1-SNAPSHOT 8 | war 9 | 10 | java_oauth 11 | http://maven.apache.org 12 | 13 | 14 | cc.moko.weixin.Application 15 | UTF-8 16 | 17 | 18 | 19 | org.springframework.boot 20 | spring-boot-starter-parent 21 | 1.4.2.RELEASE 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | com.squareup.okhttp3 31 | okhttp 32 | 3.2.0 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-maven-plugin 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-compiler-plugin 45 | 46 | 1.8 47 | 1.8 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #### java 实现第三方登录 2 | 3 | * QQ 4 | 5 | * 微博 -------------------------------------------------------------------------------- /src/main/java/org/yangjie/Application.java: -------------------------------------------------------------------------------- 1 | package org.yangjie; 2 | 3 | 4 | import org.apache.log4j.Logger; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | /** 9 | * 程序入口, 启动器 10 | * @author YangJie [2015年11月4日 下午1:28:33] 11 | */ 12 | @SpringBootApplication 13 | public class Application { 14 | 15 | private static Logger logger = Logger.getLogger(Application.class); 16 | 17 | public static void main(String[] args) { 18 | SpringApplication.run(Application.class, args); 19 | logger.info("server is running..."); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/yangjie/config/WebMvcConfig.java: -------------------------------------------------------------------------------- 1 | package org.yangjie.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 6 | 7 | /** 8 | * web mvc 配置类 9 | * @author YangJie [2015年11月4日 下午1:30:08] 10 | */ 11 | @Configuration 12 | public class WebMvcConfig extends WebMvcConfigurerAdapter { 13 | 14 | @Override // 默认首页 15 | public void addViewControllers(ViewControllerRegistry registry) { 16 | registry.addViewController("/").setViewName("/login.html"); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/yangjie/controller/QQController.java: -------------------------------------------------------------------------------- 1 | package org.yangjie.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | import org.yangjie.service.QQService; 8 | 9 | /** 10 | * QQ登录 11 | * @author YangJie [2017年2月23日 下午3:54:16] 12 | */ 13 | @Controller 14 | @RequestMapping("qq") 15 | public class QQController{ 16 | 17 | @Autowired 18 | private QQService qqService; 19 | 20 | 21 | /** 22 | * 登录发起 23 | * @author YangJie [2017年2月22日 下午6:28:49] 24 | * @return 25 | */ 26 | @RequestMapping(value="/auth", method=RequestMethod.GET) 27 | public String auth() { 28 | String url = new StringBuilder(QQService.AUTH_URL) 29 | .append("?client_id=").append(QQService.APPID) 30 | .append("&redirect_uri=").append(QQService.CALLBACK_URL) 31 | .append("&response_type=code&state=moko").toString(); 32 | return "redirect:" + url; 33 | } 34 | 35 | /** 36 | * 登录授权回调 37 | * @author YangJie [2017年2月22日 下午6:28:49] 38 | * @param code 39 | * @param state 40 | * @return 41 | */ 42 | @RequestMapping(value="/callback", method=RequestMethod.GET) 43 | public String callback(String code, String state) { 44 | String token = qqService.getToken(code); 45 | String openid = qqService.getOpenid(token); 46 | // 执行登录过程, 然后调整到个人首页 47 | return "redirect:/my.html?"+openid; 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/main/java/org/yangjie/controller/WeiboController.java: -------------------------------------------------------------------------------- 1 | package org.yangjie.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | import org.yangjie.service.WeiboService; 8 | 9 | /** 10 | * 微博登录 11 | * @author YangJie [2017年2月23日 下午3:54:01] 12 | */ 13 | @Controller 14 | @RequestMapping("weibo") 15 | public class WeiboController{ 16 | 17 | @Autowired 18 | private WeiboService weiboService; 19 | 20 | 21 | /** 22 | * 登录发起 23 | * @author YangJie [2017年2月22日 下午6:28:49] 24 | * @return 25 | */ 26 | @RequestMapping(value="/auth", method=RequestMethod.GET) 27 | public String auth() { 28 | String url = new StringBuilder(WeiboService.AUTH_URL) 29 | .append("?client_id=").append(WeiboService.APPID) 30 | .append("&redirect_uri=").append(WeiboService.CALLBACK_URL) 31 | .append("&state=moko").toString(); 32 | return "redirect:" + url; 33 | } 34 | 35 | /** 36 | * 登录授权回调 37 | * @author YangJie [2017年2月22日 下午6:28:49] 38 | * @param code 39 | * @param state 40 | * @return 41 | */ 42 | @RequestMapping(value="/callback", method=RequestMethod.GET) 43 | public String callback(String code, String state) { 44 | String uid = weiboService.getUid(code); 45 | // 执行登录过程, 然后调整到个人首页 46 | return "redirect:/my.html?"+uid; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/main/java/org/yangjie/service/QQService.java: -------------------------------------------------------------------------------- 1 | package org.yangjie.service; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.stereotype.Service; 7 | import org.yangjie.util.HttpUtil; 8 | import org.yangjie.util.JsonUtil; 9 | 10 | /** 11 | * QQ登录 12 | * @author YangJie [2017年2月23日 下午2:47:29] 13 | */ 14 | @Service 15 | public class QQService{ 16 | 17 | public static String APPID = ""; 18 | public static String SECRET = ""; 19 | public static String CALLBACK_URL = "http:///qq/callback"; 20 | 21 | // 发起授权地址 22 | public static String AUTH_URL = "https://graph.qq.com/oauth2.0/authorize"; 23 | // 获取token地址 24 | public static String TOKEN_URL = "https://graph.qq.com/oauth2.0/token"; 25 | // 获取授权信息地址 26 | public static String ME_URL = "https://graph.qq.com/oauth2.0/me"; 27 | // 获取用户信息地址 28 | public static String INFO_URL = "https://graph.qq.com/user/get_user_info"; 29 | 30 | 31 | /** 32 | * 获取token 33 | * @author YangJie [2017年2月22日 下午6:28:49] 34 | * @param code 35 | * @return 36 | */ 37 | public String getToken(String code) { 38 | String url = new StringBuilder(TOKEN_URL) 39 | .append("?client_id=").append(APPID) 40 | .append("&client_secret=").append(SECRET) 41 | .append("&grant_type=").append("authorization_code") 42 | .append("&redirect_uri=").append(CALLBACK_URL) 43 | .append("&code=").append(code).toString(); 44 | String result = HttpUtil.get(url); 45 | // access_token=x&expires_in=x&refresh_token=x 46 | return result.split("&")[0].split("=")[1]; 47 | } 48 | 49 | /** 50 | * 获取openid 51 | * @author YangJie [2017年2月22日 下午6:28:49] 52 | * @param token 53 | * @return 54 | */ 55 | public String getOpenid(String token) { 56 | String url = new StringBuilder(ME_URL) 57 | .append("?access_token=").append(token).toString(); 58 | // 如果申请过多应用联合, 可以通过添加参数&unionid=1获取 59 | String result = HttpUtil.get(url); 60 | // callback( {"client_id":"x","openid":"x"} ); 61 | return result.split("\"")[7]; 62 | } 63 | 64 | 65 | /** 66 | * 获取用户信息 67 | * @author YangJie [2017年2月22日 下午6:28:49] 68 | * @param openid 69 | * @param token 70 | * @return http://wiki.connect.qq.com/get_user_info 71 | */ 72 | public Map getInfo(String openid, String token) { 73 | String url = new StringBuilder(INFO_URL) 74 | .append("?oauth_consumer_key=").append(APPID) 75 | .append("&openid=").append(openid) 76 | .append("&access_token=").append(token).toString(); 77 | String result = HttpUtil.get(url); 78 | return JsonUtil.toObject(result, HashMap.class, Map.class, String.class, String.class); 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /src/main/java/org/yangjie/service/WeiboService.java: -------------------------------------------------------------------------------- 1 | package org.yangjie.service; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.stereotype.Service; 7 | import org.yangjie.util.HttpUtil; 8 | import org.yangjie.util.JsonUtil; 9 | 10 | /** 11 | * 微博登录 12 | * @author YangJie [2017年2月23日 下午2:47:29] 13 | */ 14 | @Service 15 | public class WeiboService{ 16 | 17 | public static String APPID = ""; 18 | public static String SECRET = ""; 19 | public static String CALLBACK_URL = "http:///weibo/callback"; 20 | 21 | // 发起授权地址 22 | public static String AUTH_URL = "https://api.weibo.com/oauth2/authorize"; 23 | // 获取token地址 24 | public static String TOKEN_URL = "https://api.weibo.com/oauth2/access_token"; 25 | // 获取用户信息地址 26 | public static String INFO_URL = "https://api.weibo.com/2/users/show.json"; 27 | 28 | 29 | /** 30 | * 获取uid 31 | * @author YangJie [2017年2月22日 下午6:28:49] 32 | * @param code 33 | * @return 34 | */ 35 | public String getUid(String code) { 36 | Map formMap = new HashMap(); 37 | formMap.put("client_id", APPID); 38 | formMap.put("client_secret", SECRET); 39 | formMap.put("grant_type", "authorization_code"); 40 | formMap.put("redirect_uri", CALLBACK_URL); 41 | formMap.put("code", code); 42 | String result = HttpUtil.post(TOKEN_URL, formMap); 43 | // {"access_token": "ACCESS_TOKEN","expires_in": 1234,"remind_in":"798114","uid":"12341234"} 44 | Map resultMap = JsonUtil.toObject(result, HashMap.class, Map.class, String.class, String.class); 45 | return resultMap.get("uid"); 46 | } 47 | 48 | /** 49 | * 获取用户信息 50 | * @author YangJie [2017年2月22日 下午6:28:49] 51 | * @param uid 52 | * @param token 53 | * @return http://open.weibo.com/wiki/2/users/show 54 | */ 55 | public Map getInfo(String uid, String token) { 56 | String url = new StringBuilder(INFO_URL) 57 | .append("?access_token=").append(token) 58 | .append("&uid=").append(uid).toString(); 59 | String result = HttpUtil.get(url); 60 | return JsonUtil.toObject(result, HashMap.class, Map.class, String.class, String.class); 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /src/main/java/org/yangjie/util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package org.yangjie.util; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | 6 | import okhttp3.FormBody; 7 | import okhttp3.MediaType; 8 | import okhttp3.OkHttpClient; 9 | import okhttp3.Request; 10 | import okhttp3.RequestBody; 11 | 12 | /** 13 | * HTTP工具类 14 | * @author YangJie [2016年5月24日 下午6:15:41] 15 | */ 16 | public class HttpUtil { 17 | 18 | private static final OkHttpClient client = new OkHttpClient(); 19 | 20 | private static final MediaType jsonMediaType = MediaType.parse("application/json; charset=utf-8"); 21 | private static final MediaType xmlMediaType = MediaType.parse("application/xml; charset=utf-8"); 22 | 23 | 24 | 25 | /** 26 | * execute 27 | * @param request 28 | * @return 29 | */ 30 | public static String execute(Request request){ 31 | try { 32 | return client.newCall(request).execute().body().string(); 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | } 36 | return null; 37 | } 38 | 39 | /** 40 | * get 41 | * @param url 42 | * @return 43 | * @throws Exception 44 | */ 45 | public static String get(String url) { 46 | return execute(new Request.Builder().url(url).get().build()); 47 | } 48 | 49 | /** 50 | * post 51 | * @param url 52 | * @param body 53 | * @return 54 | */ 55 | public static String post(String url, RequestBody body){ 56 | return execute(new Request.Builder().url(url).post(body).build()); 57 | } 58 | 59 | /** 60 | * post 61 | * @param url 62 | * @param formMap 63 | * @return 64 | */ 65 | public static String post(String url, Map formMap){ 66 | FormBody.Builder form = new FormBody.Builder(); 67 | if (formMap!=null && !formMap.isEmpty()) { 68 | for(String key : formMap.keySet()){ 69 | form.add(key, formMap.get(key)); 70 | } 71 | return post(url, form.build()); 72 | } 73 | return null; 74 | } 75 | 76 | /** 77 | * post 78 | * @param url 79 | * @param body 80 | * @param mediaType 81 | * @return 82 | */ 83 | public static String post(String url, String body, MediaType mediaType) { 84 | return post(url, RequestBody.create(mediaType, body)); 85 | } 86 | 87 | /** 88 | * post (json) 89 | * @param url 90 | * @return 91 | */ 92 | public static String postJson(String url, String body) { 93 | return post(url, body, jsonMediaType); 94 | } 95 | 96 | /** 97 | * post (xml) 98 | * @param url 99 | * @param body 100 | * @return 101 | */ 102 | public static String postXml(String url, String body) { 103 | return post(url, body, xmlMediaType); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/org/yangjie/util/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package org.yangjie.util; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.DeserializationFeature; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | 7 | public class JsonUtil { 8 | 9 | public static ObjectMapper objectMapper = new ObjectMapper() 10 | .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 忽略未知属性 11 | 12 | /** 13 | * 将对象转换成json字符串 14 | * @param object 15 | * @return 16 | * @throws Exception 17 | */ 18 | public static String toJson(Object object) { 19 | try { 20 | return objectMapper.writeValueAsString(object); 21 | } catch (JsonProcessingException e) { 22 | e.printStackTrace(); 23 | } 24 | return null; 25 | } 26 | 27 | /** 28 | * 将json字符串转换成对象 29 | * @param json 30 | * @param valueType 31 | * @return 32 | * @throws Exception 33 | */ 34 | public static T toObject(String json, Class valueType) { 35 | try { 36 | return objectMapper.readValue(json, valueType); 37 | } catch (Exception e) { 38 | e.printStackTrace(); 39 | } 40 | return null; 41 | } 42 | 43 | /** 44 | * json转对象(处理复杂类型对象) 45 | * List : json, ArrayList.class, List.class, Bean.class 46 | * Map : json, HashMap.class, Map.class, Bean1.class, Bean2.class 47 | * @param json 48 | * @param parametrized 要转换的真实类型 49 | * @param parametersFor 要转换类型的类或接口 50 | * @param parameterClasses 类型中的泛型类型 51 | * @return 52 | * @throws Exception 53 | */ 54 | public static T toObject(String json, Class parametrized, Class parametersFor, Class... parameterClasses) { 55 | try { 56 | return objectMapper.readValue(json, objectMapper.getTypeFactory().constructParametrizedType(parametrized, parametersFor, parameterClasses)); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | return null; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 80 -------------------------------------------------------------------------------- /src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 第三方登录 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/main/webapp/my.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | index 6 | 7 | 8 | 9 | index 10 | 11 | 12 | --------------------------------------------------------------------------------