开放平台-web实现人人网第三方登录

来源:互联网 发布:2017大数据领军人物 编辑:程序博客网 时间:2024/05/17 02:41

应用场景

    web应用通过人人网登录授权实现第三方登录。
 

操作步骤

    1  注册成为人人网开放平台开发者
        http://app.renren.com/developers/devinfo
 
    2  准备一个可访问的域名,如dev.foo.com
    3  创建网页应用,配置必要信息,其中包括根域名、图标信息
 
    4  获取应用appID、appKey进行开发
 

登录流程

    采用server-side方式实现登录授权,流程如下
 
    
 
    流程描述
    1  server端页面跳转到登录授权页面(Authorization code方式)
    2   回调获得code 
    3   置换accessToken,同时也得到uid、用户资料信息
    4   同步用户信息并登录
 
    OAuth2.0 采用Authorization code方式将更为可靠、安全。
    更多信息可参考人人网开放平台wiki:
    http://wiki.dev.renren.com/wiki/Authentication#.E6.9C.8D.E5.8A.A1.E7.AB.AF.E6.8E.88.E6.9D.83
 

案例实战

    本地开发环境准备

        修改hosts文件将dev.foo.com映射到127.0.0.1;
        本地服务器以80端口启动, windows下可能会出现80端口被系统进程占用的情况,解决方法可参考 http://www.cnblogs.com/littleatp/p/4414578.html
        本地服务器启动后,以dev.foo.com的域名进行访问,在登录授权时可通过域名验证这一步
 

    前端登录跳转页面

<html>     <head>        <title>人人网登录跳转</title>        <script src="http://lib.sinaapp.com/js/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>                <script type="text/javascript">        //应用的APIKEY        var apiKey = "3ce9cb1e264f4e93b1f38807be66e629";       //成功授权后的回调地址        var redirectUrl = "@@{openapi.Renrens.callback()}";        var authorizeUrl = "https://graph.renren.com/oauth/authorize?"        var queryParams = ['client_id=' + apiKey,'redirect_uri=' + redirectUrl,'response_type=code'];        var url = authorizeUrl + queryParams.join('&');                //打开授权登录页面        window.location.href= url;        </script>     </head>          <body>     </body></html>

 

        功能描述
        页面在打开时直接跳转到人人网登录授权页面,此后授权成功后将回调至redirect_uri
 

   server端处理回调,同步信息

    授权回调的页面处理
/**     * 授权回调     *     * @param code     * @param error     */    public static void callback(String code) {        if (!StringUtils.isEmpty(code)) {            error("授权失败");        }         // 根据code换取accesstoken,包括用户信息        // ...         String callbackUrl = RouteContext.getUrl("openapi.Renrens.callback", Collections.EMPTY_MAP,                true);        RenrenToken token = RenApi.getTokenInfo(code, callbackUrl);        if (token == null) {            error("授权失败:无法获取连接系统");        }        render(code, token);    }

 

    数据对象
   
RenrenToken类
/** * 返回token数据对象 *  * <pre> *      * {     *   "token_type":"bearer", *   "expires_in":2595096, *   "refresh_token":"127021|0.KAS3b8doSitHk6RLDtitb2VY8PjktTRA.229819774.1376381303243", *   "user":{ *     "id":229819700, *     "name":"二小姐", *     "avatar":[ *         {   "type":"avatar", *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_head_KFTQ_d536000000d0111b.jpg" *         }, *         {   "type":"tiny", *         "url":"http://hdn.xnimg.cn/photos/hdn221/20130805/2055/tiny_jYQe_ec4300051e7a113f.jpg" *         }, *         {   "type":"main", *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_main_ksPJ_d536000000d0111b.jpg"}, *         {   "type":"large", *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_large_yxZz_d536000000d0111b.jpg" *         } *     ] *   }, *   "access_token":"127066|6.08718aa138db0578dda3250f33bads6e.2592000.1378976400-229819774" *   "scope":"read_user_feed read_user_album", * </pre> *  * @author littleatp * @createDate 2015年4月14日 *  */public class RenrenToken {    public String token_type;    public int expires_in;    public String refresh_token;    public String access_token;    public String scope;    public RenrenUser user;}

 

RenrenUser类
/** * 人人网用户信息 *  * <pre> * "user":{ *     "id":229819700, *     "name":"二小姐", *     "avatar":[ *         {   "type":"avatar", *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_head_KFTQ_d536000000d0111b.jpg" *         }, *         {   "type":"tiny", *         "url":"http://hdn.xnimg.cn/photos/hdn221/20130805/2055/tiny_jYQe_ec4300051e7a113f.jpg" *         }, *         {   "type":"main", *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_main_ksPJ_d536000000d0111b.jpg"}, *         {   "type":"large", *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_large_yxZz_d536000000d0111b.jpg" *         } *     ] *   }, * </pre> *  * @author littleatp * @createDate 2015年4月14日 *  */public class RenrenUser {    public long id;    public String name;    public List<RenrenAvatar> avatar;    public String getAvatarUrl() {        if (avatar == null || avatar.isEmpty()) {            return "";        }        return avatar.get(0).url;    }    public static class RenrenAvatar {        public String type;        public String url;    }}

 

RenApi功能实现
/** * 人人网API *  * <pre> * 登录流程: *  * 1 前端跳转人人网授权(code方式) * 2 回调获得authorize code * 3 通过code换取access_token * 4 获得token及用户信息 *  * 参考文档: * http://wiki.dev.renren.com/wiki/Authentication * </pre> *  *  * @author littleatp * @createDate 2015年4月10日 *  */public class RenApi {    public static String apiKey = "xxx";    public static String secretKey = "xxx";    public static String baseUrl = "https://graph.renren.com/oauth";    protected static final String URL_GET_TOKEN = baseUrl + "/token?grant_type=authorization_code"            + "&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s";    protected static final long ACCESS_TIMEOUT = 15;    protected static final String DEF_APP_TOKEN_EXPIRE = "3h";/**     * 获取token信息     *      * <pre>     * http://wiki.dev.renren.com/wiki/Authentication#.E5.AE.A2.E6.88.B7.E7.AB.AF.E6.8E.88.E6.9D.83     * 返回token的同时也附带了用户信息     *      * 调用地址:     * https://graph.renren.com/oauth/token     *      * 参数     * grant_type:使用Authorization Code 作为Access Grant时,此值固定为“authorization_code”;     * client_id:在开发者中心注册应用时获得的API Key;     * client_secret:在开发者中心注册应用时获得的Secret Key。Secret Key是应用的保密信息,请不要将其嵌入到服务端以外的代码里;     * redirect_uri:必须与获取Authorization Code时传递的“redirect_uri”保持一致;     * code:上述过程中获得的Authorization Code。     *      * 返回结果如下:     * {         *   "token_type":"bearer",     *   "expires_in":2595096,     *   "refresh_token":"127021|0.KAS3b8doSitHk6RLDtitb2VY8PjktTRA.229819774.1376381303243",     *   "user":{     *     "id":229819700,     *     "name":"二小姐",     *     "avatar":[     *         {   "type":"avatar",     *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_head_KFTQ_d536000000d0111b.jpg"     *         },     *         {   "type":"tiny",     *         "url":"http://hdn.xnimg.cn/photos/hdn221/20130805/2055/tiny_jYQe_ec4300051e7a113f.jpg"     *         },     *         {   "type":"main",     *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_main_ksPJ_d536000000d0111b.jpg"},     *         {   "type":"large",     *         "url":"http://hdn.xnimg.cn/photos/hdn121/20130805/2055/h_large_yxZz_d536000000d0111b.jpg"     *         }     *     ]     *   },     *   "access_token":"127066|6.08718aa138db0578dda3250f33bads6e.2592000.1378976400-229819774"     *   "scope":"read_user_feed read_user_album",     * }     *      * 错误返回:     * {     *   "error": "invalid_grant",     *   "error_code": 20204     *   "error_description": "Invalid authorization code: 9OCQp3IzRcwtSRPKOEUKiRRsz9SUNgdE"     * }     * http://wiki.dev.renren.com/wiki/%E9%94%99%E8%AF%AF%E5%93%8D%E5%BA%94     * </pre>     *      * @param accessToken     * @return     */    public static RenrenToken getTokenInfo(String code, String callbackUrl) {        if (StringUtils.isEmpty(code)) {            return null;        }        String url = String.format(URL_GET_TOKEN, apiKey, secretKey, code, callbackUrl);        String resultString = DefaultHttp.get(url, ACCESS_TIMEOUT, GlobalConstants.UTF_8);        Logger.debug("[sso-renren]get token. use url '%s'", url);        RenrenToken token = JsonUtil.fromJson(resultString, RenrenToken.class);        if (token == null || StringUtils.isEmpty(token.access_token)) {            Logger.debug("[sso-renren]get token failed, with result of '%s'", resultString);            return null;        }        Logger.debug("[sso-renren]get token success, with result of '%s'", resultString);        return token;    }}

 

关于CSRF

    跨站攻击问题CSRF
    什么是CSRF? 可参考下http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html
 
    场景
    A网站接入了人人网开放平台,但apikey和secretkey通过页面泄露了出去;
    B网站根据同样的apikey和secretkey仿造authorize请求,获得authorization code;
    B网站直接跳转到A网站的callback页面;
    A网站按授权流程获得用户信息并登录;
 
    这样B网站便成功实现了仿造请求登录A网站的功能;
 
    解决方法
    在向平台请求授权(authorize)时可带上一个state参数,建议该参数由A网站动态生成。
    平台调用callback时会回传该state参数,此时A网站需要在callback处理时对该参数进行验证
    于是B网站无法伪造state参数,也就无法伪造登录场景了。
 

常见问题

 
网页跳转提示 
        redirect_uri_mismatch
        通常是应用配置中的根域名与当前开发服务器访问地址不一致导致
 
授权返回错误
       检查返回的error代码
       http://wiki.dev.renren.com/wiki/%E9%94%99%E8%AF%AF%E5%93%8D%E5%BA%94
 
SDK的使用
        对于强依赖于人人网平台的应用,建议使用下平台的SDK,如JavaSDK;其封装了大量api访问及出错处理细节,可提高开发效率。
        参考:http://wiki.dev.renren.com/wiki/V2/sdk/java_sdk
    
原文地址:http://littleatp.cnblogs.com/p/4430297.html
1 0
原创粉丝点击