openid4java 使用记录[转载]
【文章来源:http://r-j-r-a5438-163-com.iteye.com/blog/611351】
在项目中使用了openid4java进行开发,在开发过程中碰到过一些问题,在网上也找了很久仍然没有答案,最后通过查看原码才把问题解决,希望在此记录能帮助后来者。
1、推荐http://code.google.com/p/openid4java ,在这上面能下到源码及一些常用的使用说明。
2、转载一片开发过程中参考的文章:
OpenID4Java现在实现了OpenID1.1和OpenID2.0规范。但是对于属性交换规范支持的不是很好,不过好像这也不能怪人家OpenID4Java,某些openid provider不按照规矩来(比如google),某些Provider是按照规矩来了,但是现在还处于测试期 (比如yahoo!),属性交换的功能只是提供给有限的几个站点(plaxo,Jyte)—可怜我捣鼓了两天之后才偶然间发现这个噩耗,呃…无语
OpenID4Java现在由code.google.com来维护,可在http://code.google.com/p/openid4java/下载,当前版本是openid4java-0.9.2-bundle.jar。呃...刚想查一下版本号,突然发现怎么有个Deprecated标记,难道夭折了?
不管它了,还是看看OpenID4Java怎么使用比较重要,这才是本文的目的所在不是J
第一步:创建ConsumerManager对象,这个对象是保持与OP端的通信的,所以说在认证会话的整个生命周期中,RP需要保证ConsumerManager是同一个实例化对象。
if(application.getAttribute("consumermanager") == null){ConsumerManager newmgr=new ConsumerManager();newmgr.setAssociations(new InMemoryConsumerAssociationStore());newmgr.setNonceVerifier(new InMemoryNonceVerifier(5000));application.setAttribute("consumermanager",newmgr);}
这里我们将对象设置为application范围,目的是将相关密钥保存在同一位置,以免在大量请求到来时,引起性能下降。setAssociations方法设置与OP的关联存放的位置,你可以把它存在内存或者数据库或者xml或者文件中,这个随你喜欢咯,这里我们将它存放在内存。setNonceVerifier方法设置记录response_nonce
的位置。
万事俱备,只欠redirect(如果你不需要什么特殊服务的话J):
现在RP可以将用户重定向到OP,当然你需要设置好return_url,告诉OP认证完成之后返回到哪个URL,我们在那个URL进行后续的处理。
String returnToUrl = "http://xxx.xxx.com/openid_returnurl.jsp"; //比较重要,通过关联句柄以及returnURL准备OP需要的参数以及参数值 AuthRequest authReq = manager.authenticate(discovered, returnURL); //重定向到OP认证 request.sendRedirect(authReq.getDestinationUrl(true));
以上这三行代码准备好op需要的参数以及参数值,将用户重定向到OP,在OP端,用户输入用户名密码或者其他方式登录系统,OP会询问用户是否同意RP的认证请求。
注意:以上代码只是在RP不需要用户提供其他信息的情况下的代码,如果要求用户提供其他信息,比如email,gender,date of birth,country等等需要在重定向之前添加额外的请求参数。比如RP可以要求用户必须提供email,有选择的提供性别,生日,国家等信息:
OpenID协议提供了两种方式获取用户信息:
第一种:
AuthRequest authReq = manager.authenticate(discovered,returnToUrl); FetchRequest fetch = FetchRequest.createFetchRequest(); fetch.addAttribute("email", "http://axschema.org/contact/email", true); fetch.addAttribute("gender", " http://schema.openid.net/contact/gender ", false); fetch.addAttribute("dob", " http://schema.openid.net/contact/language", false); fetch.addAttribute("country", " http://schema.openid.net/contact/country", false); authReq.addExtension(fetch);
第二种:
SRegRequest regReq = SRegRequest.createFetchRequest(); regReq.addAttribute("email",true); regReq.addAttribute("gender",false); regReq.addAttribute("dob",false);’ regReq.addAttribute("country",false); authReq.addExtension(regReq);
需要注意的是并不是所有的OP都支持两种方式获取用户信息。通过google提供的OpenID API可以看到google只支持第一种方式,而且要求参数必须是openid.ns.ext1 openid.ext1.mode,openid.ext1.type.email,openid.ext1.required,可以看到google要求参数名必须是ext1的形式。
而且查看openid4java的源代码可以看到使用addExtension方法并不是很好。所以建议如果需要获取用户信息可以将两种获取信息的方式都加上,而且最好是第一种在前,第二种在后。如果将第一种放在后面,最后提交给OP数就会变成ext0的形式。google就会认为不是合法的请求,所以不提供email(当前google只提供用户的email信息,其他信息暂时无法提供)
有关google openid api的具体信息可以参考http://code.google.com/intl/zh-CN/apis/accounts/docs/OpenID.html
另外如果不想受两种获取信息方法顺序的限制,还可以有两种办法解决参数问题:
1重写或者重载Message.addExtension(MessageExtension extension)方法修改参数生成规则。
2 regReq.getParameters().set(new Parameter("openid.ext1.required ","email"));直接设置必须的参数。
另外:openid4java-0.9.2(也就是最新版本)中使用的属性交换协议是http://openid.net/srv/ax/1.0-draft,而google要求属性交换协议要求是http://openid.net/srv/ax/1.0需要单独设置,如果设置不正确,仍然不能获取到用户信息。
用户同意RP的认证请求之后,OP便将用户重定向到RP,并发送认证信息给RP,RP需要接受认证信息,检查是否认证通过,获取用户信息,然后进行后续的处理。
//获取ConsumerManager认证对象 ConsumerManager manager=(ConsumerManager)application.getAttribute("consumermanager"); //获取响应参数列表 ParameterList params = new ParameterList(request.getParameterMap()); DiscoveryInformation discovered = (DiscoveryInformation)session.getAttribute("discovered"); StringBuffer url = request.getRequestURL(); String query = request.getQueryString(); if(StringUtils.isNotBlank(query)){url.append("?").append(query); } //根据参数列表,关联句柄以及url_query验证是否通过认证 VerificationResult verification = manager.verify(url.toString(),params,discovered); Ientifier verified = verification.getVerifiedId();
上面谈到的两种获取用户属性的方式处理是不同的,所以在return_url中这两种方式都要考虑到。
if(verified != null){String email = null;AuthSuccess authSuccess = (AuthSuccess)verification.getAuthResponse();if(authSuccess.hasExtension(SRegMessage.OPENID_NS_SREG)){MessageExtension ext = authSuccess.getExtension(SRegMessage.OPENID_NS_SREG);if(ext instanceof SRegResponse){SRegResponse regResp = (SRegResponse)ext;email = regResp.getAttributeValue("email");}}else if (authSuccess.hasExtension(AxMessage.OPENID_NS_AX)){MessageExtension ext = authSuccess.getExtension(AxMessage.OPENID_NS_AX);if (ext instanceof FetchResponse){FetchResponse fetchResp = (FetchResponse) ext;email = (String)fetchResp.getAttributeValues("email").get(0);}}if(StringUtils.isBlank(email));// OpenID中没有提供Email信息//后续的处理 }
以上是RP Consumer与OP的交互过程,这个过程能保证与大部分的OP通信没有问题,但是有少数号称完全遵守规范OpenID2.0的OP站点仍然有一些小问题(比如yahoo!),当然使用这段代码还是可以通过认证的,但是yahoo!会给用户一个大大的提示:Warning: This website does not meet Yahoo!'s requirements for website address. Do not share any personal information with this website unless you are certain that it is legitimate.
3、遇到的问题:
1)OP端使用SRegResponse传递参数时,在RP端进行校 验总是失败,经过查看源码,发现OP端在((AuthSuccess)responsem).addExtension(sResp);时,将会修改 responsem中openid.signed的值,但是openid.sig的值确没有修改,因此到了RP端进行签名校验时不能通过,因此解决方法就 是在addExtension后,重新进行一次签名amanager.sign((AuthSuccess)responsem);终于把问题解决。
openid4java 使用记录[转载]相关推荐
- hadoop恢复记录-转载
摘自:http://hmilyzhangl.iteye.com/blog/1407214 一.崩溃原因 搭建的是一个hadoop测试集群,所以将数据备份参数设置为dfs.replication=1,这 ...
- Spring Mvc返回html页面404错误解决记录--转载
原文地址:http://53873039oycg.iteye.com/blog/2061992 以前使用Spring Mvc时候都是返回jsp页面或者ftl页面,昨天想返回html页面,spring- ...
- Cloudera Manager 和CDH6.0.1安装,卸载,各步骤截图(此博文为笔者辛苦劳作最终生成的,使用了3个熬到凌晨2~4点的夜晚,外加一个周末完成,请转载时记录转载之处,谢谢)
1 Cloudera 文档总地址 https://www.cloudera.com/documentation/enterprise/6/6.0.html 2 Cloudera Manager 和CD ...
- scala版本的springboot的helloworld实验记录(转载+自己验证整理)
实验结构如下: ├── pom.xml ├── src │ └── main │ └── scala │ ├── AppConf.scala │ ...
- flink1.12在ubuntu下面的编译记录(转载+自己整理)
##############一些概念和小技巧######################### git clone https://gitee.com/fastsource/flink 如何判断当前版 ...
- 数据库删除记录核心语句 解读 (vb6.0)
str2$ = MsgBox("是否删除当前记录?", vbOKOnly + vbExclamation, "提示") If str2$ = vbOK Then ...
- 2017年7月十三日正式开始记录
2017年7月十三日正式开始记录 转载于:https://blog.51cto.com/13022137/1947342
- 不同数据库中查询前几条记录的用法(SQL Server/Oracle/Postgresql)
SQL在不同数据库中查询前几条记录的用法分类 1. orACLE Select * FROM TABLE1 Where ROWNUM<=N 2. INFORMIX Select FIRST N ...
- SQL 去除重复记录 只保留重复记录中的一条
select a.* from USERLOGGERFILTER a where loggertime > '2010-05-31' and loggertime < '2010-06- ...
最新文章
- ASP.NET页生命周期概述
- PHP7 RC7 Release对比PHP5.6快速排序20000数据性能体验以及新语法尝鲜
- leetcode102 二叉树的层次遍历
- python语言怎么学-如何学习Python,以及新手如何入门?
- 产品经理整理PRD时,需要注意哪些点
- 阿里资深技术工程师: 程序员怎样快速成长?
- HTML的onclick的this指向
- 《Linux多线程服务端编程——使用muduo C++网络库》读书笔记
- 解决:If the number of processors is expected to increase from one, then you should configure the numbe
- linux dns 问题吗,Linux下DNS的问题
- AndroidStudio_后台服务以及活动和服务间通信_通过service中的binder实现活动和服务的通信---Android原生开发工作笔记216
- 训练及优化神经网络基本流程之第0到6步
- 82相似标准形03——不变因子、行列式因子、相抵标准形的唯一性、用求行列式因子法求标准形
- 谷歌地球大陆版如何下载和使用,查看谷歌历史影像3D建筑街景等
- 【74HC595】STM32 74HC595驱动程序
- mp3文件合并java_Android - 合并mp3文件
- VB制作的“小小莫扎特五线谱助记软件”
- 第14节 三个败家子(14)——在辉煌中走向深渊
- 打印机用计算机名慢,“电脑连上打印机就超级慢”的解决方案
- CUDA C/C++ 流和并发