基于OAuth2.0实现第三方授权登陆(百度账号)

大致说下整个流程:


1. 注册百度开发者 http://developer.baidu.com/ 获取key secret等值, 同时定义自己的授权回掉页。


2. 寻找API, OAuth的相关API在  http://developer.baidu.com/ms/oauth


3. 引导用户进行授权 

http://openapi.baidu.com/oauth/2.0/authorize?
	response_type=code&
	client_id=YOUR_CLIENT_ID&
	redirect_uri=YOUR_REGISTERED_REDIRECT_URI
   


4. 根据得到的Code, 进行AccessToken的获取

https://openapi.baidu.com/oauth/2.0/token?
	grant_type=authorization_code&
	code=CODE&
	client_id=YOUR_CLIENT_ID&
	client_secret=YOUR_CLIENT_SECRET&
	redirect_uri=YOUR_REGISTERED_REDIRECT_URI


5. 获取用户信息

https://openapi.baidu.com/rest/2.0/passport/users/getInfo?access_token=1.a6b7dbd428f731035f771b8d15063f61.86400.1292922000-2346678-124328 HTTP/1.1

下面贴上核心代码:


配置文件


<?xml version="1.0" encoding="UTF-8"?>
<config id="baidu">
	<params>
		<param name="clientId" value="6422351" />
		<param name="apiKey" value="i3sM3nVMGv46w4eHLgpSQ4GP" />
		<param name="secretKey" value="Gbw9IjqOVeP63AGQi2O0RaPSkLjMfLto" />
		<param name="scope" value="" />
		<param name="redirectUri" value="http://localhost:8080/third_login/baidu" />
		<param name="apiBaseUrl" value="https://openapi.baidu.com/rest/2.0"></param>
	</params>
	<authUrl>
	<![CDATA[
		http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=${apiKey}&redirect_uri=${redirectUri}
	]]>
	</authUrl>
	<tokenUrl>
	<![CDATA[
		https://openapi.baidu.com/oauth/2.0/token?grant_type=authorization_code&code=${code}&client_id=${apiKey}&client_secret=${secretKey}&redirect_uri=${redirectUri}
	]]>
	</tokenUrl>
	<userInfoApi>
	<![CDATA[
		${apiBaseUrl}/passport/users/getLoggedInUser?access_token=${accessToken}
	]]>
	</userInfoApi>
	<portraitUrlTemplate>
	<![CDATA[
		http://tb.himg.baidu.com/sys/portrait/item/${portrait}
	]]>
	</portraitUrlTemplate>
</config>


ThirdLoginServlet


    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String plat = getPlatName(request);
        String code = request.getParameter("code");

        User user = OAuthHelper.getUserInfo(plat, code);
        if (user != null) {

            User persistenceUser = UserDao.findUserByThirdId(user.getThirdId());
            // 先判断third_id对应用户是否已存在
            if (persistenceUser != null) {
                // 存在表示曾经登录过,更新信息
                persistenceUser.setName(user.getName());
                UserDao.updateName(persistenceUser);// 更新姓名(昵称)
            } else {
                // 不存在表示实效使用此第三方账号登录本系统,先将用户信息写入,相当于注册的过程
                persistenceUser = UserDao.insertUser(user);
            }

            // 写头像文件
            persistenceUser.setPortraitData(user.getPortraitData());
            String basePath = request.getServletContext().getRealPath("/portrait");
            savePortrait(basePath + File.separator + persistenceUser.getId(), persistenceUser);
            

            // 将用户对象存入session,后结操作可根据session中user信息判断是否登录及登录人信息
            request.getSession().setAttribute("loginUser", persistenceUser);

            // 用户信息存入session,跳转到用户页
            toSuccessPage(plat, request, response);
        } else {
            // 授权过程出现错误,进入错误页
            toErrorPage(plat, request, response);
        }
    }

 OAuthInfo


package demo.third.model;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.fasterxml.jackson.databind.JsonNode;

/**
 * 存储oauth基本信息的类
 * 
 * @author Administrator
 *
 */
public abstract class OAuthInfo {

    private String authUrl;
    private String tokenUrl;
    private String userInfoApi;
    private String portraitUrlTemplate; // 头像图片路径模板

    private Map<String, String> params = new HashMap<String, String>();

    /**
     * 构造时从配置文件读取信息
     * 
     * @param fileName
     */
    @SuppressWarnings("unchecked")
    public OAuthInfo(String configFile) {

        InputStream is = null;
        SAXReader reader = new SAXReader();

        try {
            is = new FileInputStream(configFile);
            Document doc = reader.read(is);
            Element rootElement = doc.getRootElement();

            // 获取所有param,存入params map
            Element paramsElement = rootElement.element("params");
            List<Element> paramElements = paramsElement.elements();
            for (Element paramElement : paramElements) {
                params.put(paramElement.attributeValue("name"), paramElement.attributeValue("value"));
            }

            // 获取authUrl模板后直接用params完成模板替换,得到替换完成的authUrl
            authUrl = templateHandle(rootElement.element("authUrl").getText(), params);

            // 获取tokenUrl,替换掉固定模板值
            tokenUrl = templateHandle(rootElement.element("tokenUrl").getText(), params);

            // 获取userInfoApi
            userInfoApi = templateHandle(rootElement.element("userInfoApi").getText(), params);

            // 头像路径模板
            portraitUrlTemplate = templateHandle(rootElement.element("portraitUrlTemplate").getText(), params);
        } catch (FileNotFoundException | DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从返回的json对象中获取user信息
     * 
     * @param userNode
     * @return
     */
    public abstract User getUser(JsonNode userNode) throws IOException;

    /**
     * 验证返回的json对象是否有效,因为有可能返回的是错误信息,此时无效
     * 
     * @param userNode
     * @return
     */
    public abstract boolean userDataValidate(JsonNode userNode);

    /**
     * 引导用户浏览器跳转到授权页的路径
     * 
     * @return
     */
    public String getAuthUrl() {
        return authUrl;
    }

    /**
     * 获取access token的完整url
     * 
     * @param code
     * @return
     */
    public String getTokenUrl(String code) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("code", code);
        return templateHandle(this.tokenUrl, params);
    }

    /**
     * 获取用户api访问完整路径
     * 
     * @param accessToken
     * @return
     */
    public String getUserInfoApiUrl(String accessToken) {
        Map<String, String> params = new HashMap<String, String>();
        params.put("accessToken", accessToken);
        return templateHandle(this.userInfoApi, params);
    }

    /**
     * 下载头像图片
     * 
     * @param portrait
     * @return
     */
    protected byte[] downloadPortrait(String portrait) {

        Map<String, String> params = new HashMap<String, String>();
        params.put("portrait", portrait);
        String urlstr = templateHandle(portraitUrlTemplate, params);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            URL url = new URL(urlstr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            InputStream is = conn.getInputStream();

            byte[] buff = new byte[1024];
            int cnt;
            while ((cnt = is.read(buff)) > 0) {
                baos.write(buff, 0, cnt);
            }

            is.close();
            conn.disconnect();

            baos.close();
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 模板替换
     * 
     * @param text
     * @param params2
     * @return
     */
    private String templateHandle(String template, Map<String, String> params) {
        // 示例:
        // template =
        // "http://test.com/auth?client_id=${cid}&redirect_uri=${ruri}&auth_type=code";
        // regex = ${(.+?)},匹配${cid}, ${ruri},匹配后group(0)为${cid},group(1)为cid

        // 执行匹配操作
        Pattern regex = Pattern.compile("\\$\\{(.+?)\\}");
        Matcher matcher = regex.matcher(template);

        StringBuffer sb = new StringBuffer(); // 用来缓存替换后结果
        while (matcher.find()) { // 从字符串开头查找每个匹配项
            String key = matcher.group(1); // 找到每个匹配项后,从匹配值中取出要替换的变量名,如cid
            String replaceVal = params.get(key); // 根据变量名到map中查找要替换的值,如cid的真实值

            if (replaceVal == null) {
                // 未在参数map中找到替换值则不替换此参数,如初次处理tokenUrl时,code变量不需要替换
                continue;
            } else {
                // 用指定值替换匹配部分,如:将${cid}替换成真实cid值xxxx,并将替换后结果缓存入sb,匹配项前面的字符原样存入
                matcher.appendReplacement(sb, replaceVal);
            }
        }
        // 最后一个匹配项并替换完成后,sb中已存入到最后匹配项位置的所有替换结果
        // 最后匹配项以后的字符还没有加入,通过以下操作,将剩余字符加入,完成完整替换过程
        matcher.appendTail(sb);

        return sb.toString();
    }
}

GetUserInfo

public static User getUserInfo(String plat, String code) {

        OAuthInfo info = getInfo(plat);
        final ObjectMapper mapper = new ObjectMapper();

        try {
            String atokenUrl = info.getTokenUrl(code);
            String ret = httpGet(atokenUrl);
            JsonNode retNode = mapper.readTree(ret);
            JsonNode atokenNode = retNode.get("access_token");

            if (atokenNode == null) {
                logError(retNode, plat, code, "access_token");
                return null;
            } else {
                String apiUrl = info.getUserInfoApiUrl(atokenNode.asText());
                ret = httpGet(apiUrl);
                JsonNode userNode = mapper.readTree(ret);

                if (info.userDataValidate(userNode)) {
                    return info.getUser(userNode);
                } else {
                    logError(userNode, plat, atokenNode.asText(), "get_user");
                    return null;
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }


静态构造方法:


static {

        String configBasePath = OAuthHelper.class.getClassLoader().getResource("../config").getPath();
        //http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=i3sM3nVMGv46w4eHLgpSQ4GP&redirect_uri=http://localhost:8080/third_login/baidu
        infos.put("baidu", new OAuthInfo(configBasePath + File.separator + "baidu.xml") {
            @Override
            public User getUser(JsonNode userNode) throws IOException {
                User user = new User();
                user.setThirdId("baidu_" + userNode.get("uid").asText());
                user.setName(userNode.get("uname").asText());
                user.setPortraitData(downloadPortrait(userNode.get("portrait").asText()));
                return user;
            }

            @Override
            public boolean userDataValidate(JsonNode userNode) {
                return userNode.get("uid") != null;
            }
        });
        
        infos.put("renren", new OAuthInfo(configBasePath + File.separator + "renren.xml") {
            @Override
            public User getUser(JsonNode userNode) throws IOException {
                System.out.println(userNode);

                userNode = userNode.get("response");
                User user = new User();
                user.setThirdId("renren_" + userNode.get("id").asText());
                user.setName(userNode.get("name").asText());
                
                String portrait = userNode.get("avatar").get(1).get("url").asText();
                user.setPortraitData(downloadPortrait(portrait));
                
                return user;
            }
            
            @Override
            public boolean userDataValidate(JsonNode userNode) {
                return userNode.get("response") != null && userNode.get("response").get("id") != null;
            }
        });
    }




下载头像


 protected byte[] downloadPortrait(String portrait) {

        Map<String, String> params = new HashMap<String, String>();
        params.put("portrait", portrait);
        String urlstr = templateHandle(portraitUrlTemplate, params);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            URL url = new URL(urlstr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            InputStream is = conn.getInputStream();

            byte[] buff = new byte[1024];
            int cnt;
            while ((cnt = is.read(buff)) > 0) {
                baos.write(buff, 0, cnt);
            }

            is.close();
            conn.disconnect();

            baos.close();
            return baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }








  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值