热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

oauth2学习(一)使用Apacheoltu实现oauth2的授权服务器

     最近做oauth2预研,查了相当多的资料        因为现有的项目是使用java语言来实现的,且不打算直接去实现这一整套的标准。因此先去官网(https:oauth.

         最近做oauth2预研,查了相当多的资料

         因为现有的项目是使用java 语言来实现的,且不打算直接去实现这一整套的标准。因此先去官网(https://oauth.net/code/)看了下现有的java版实现。其实还有其他的实现没有收录进去。

 oauth2 学习(一)-使用Apache oltu实现oauth2的授权服务器

  比较之后发现资料相对较多的是Apache oltu以及 spring sercurity oauth.因为都是开源的,就去把源代码都clone下来了。个人认为Oltu相对来说更轻量,也更简单,是对oauth2的简单实现。很多后续校验的事情都需要我们自己去做,但这也是它灵活的一面。所以一开始,是决定使用Apache 的oltu。参考了杨开涛的博客(OAuth2集成——《跟我学Shiro》)使用oltu实现了一个简单的认证服务器。        

 

         一开始是打算写三个服务的oauthservice,oauthclient,oauthresource,后来为了省时间直接把客户端也集成到服务里面了,交互界面也只是几个简单的输入框。

         认证服务主要有几个接口

 

         /login:登录接口

  /Oauth/authorize:获取授权码的接口

  /Oauth/getCode:这个其实就是授权码接口,只是例子中后端没有存储登录状态,做了个中转

  /Oauth/ accesstoken:获取访问令牌

下面来说说每个接口具体做了什么事

  1. 获取授权码
    1. 将请求转换成oltu的认证请求OauthAuthzRequest
    2. 从 OauthAuthzRequest 读取客户端信息(clientId,redirectUrl,response_type)
    3. 校验客户端信息
    4. 校验成功后生成访问令牌
    5. 存储访问令牌
    6. 使用oltu的OAuthASResponse构建oauth响应
    7. 在响应中设置好授权码,state等信息
    8. 重定向到客户端的redirectUrl
      public Object getCode(HttpServletRequest request) {
      		try {
      			OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
      			OAuthResponse oAuthResponse;
      			String clientId=oauthRequest.getClientId();
      			//校验client信息
      			if(!oauthClientService.checkClient(clientId))
      			{
      				return ControllerHelper
      						.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST
      								, OAuthError.TokenResponse.INVALID_CLIENT
      								, ErrorConstants.ERROR_CLIENT_MSG);				
      			}
      			//获取登陆信息
      			//已经登录校验内部token信息,没有登陆,校验登陆信息
      			String token=request.getParameter("token");
      			if(StringUtils.isEmpty(token))//token不存在及用户没有登陆,非法访问
      			{				
      				return ControllerHelper
      						.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST
      								, OAuthError.CodeResponse.ACCESS_DENIED
      								, ErrorConstants.ERROR_CLIENT_LOGIN);
       			}
      			else {//校验token 服务器端对应的token是否存在,及获取用户信息等
      //				checktoken()
      			}
      			//生成授权码
      			String authcode=null;
      			String respOnseType=oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);
      			if(responseType.equals(ResponseType.CODE.toString()))
      			{
      				OAuthIssuerImpl oAuthIssuerImpl=new OAuthIssuerImpl(new MD5Generator());
      				authcode=oAuthIssuerImpl.authorizationCode();
      				//保存授权码
      				oauthClientService.saveCode(clientId, authcode);				
      			}
      			//Oauth 响应
      			OAuthASResponse.OAuthAuthorizationResponseBuilder builder=
      					OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);
      			//设置授权码
      			builder.setCode(authcode);
      			String redirectURI=oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
      			
      			oAuthRespOnse=builder.location(redirectURI).buildQueryMessage();
      			 //根据OAuthResponse返回ResponseEntity响应
                  HttpHeaders headers = new HttpHeaders();
                  headers.setLocation(new URI(oAuthResponse.getLocationUri()));
                  return new ResponseEntity(headers, HttpStatus.valueOf(oAuthResponse.getResponseStatus()));
      			
      			
      		} catch (Exception e) {
      			logger.error(e.getCause().getMessage(),e);
      		}
      		return null;
      	}
      

        


  2. 获取访问令牌
  1. 将请求转换成oltu的token 获取请求OAuthTokenRequest
  2. 从OauthTokenRequest读取客户端信息
  3. 校验客户端信息
  4. 生成访问令牌token
  5. 存储访问令牌
  6. 构建oauth2响应oAuthResponse
  7. 返回到客户端
public Object getToken(HttpServletRequest request) throws OAuthSystemException {
		try {
			OAuthTokenRequest oAuthTokenRequest= new OAuthTokenRequest(request);
			String clientId=oAuthTokenRequest.getClientId();
			String clientKey= oAuthTokenRequest.getClientSecret();
			
			if(!oauthClientService.checkClient(clientId,clientKey))
			{
				return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, OAuthError.TokenResponse.INVALID_CLIENT, ErrorConstants.ERROR_CLIENT_MSG);
			}
			OAuthResponse oAuthResponse;
			
			String authcode= oAuthTokenRequest.getCode();
			String grantType= oAuthTokenRequest.getGrantType();
			if(GrantType.AUTHORIZATION_CODE.toString().equals(grantType) && authcode.equals(oauthClientService.getCode(clientId)))
			{
				//生成token				
	            OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
	            final String accessToken = oauthIssuerImpl.accessToken();
	            oauthClientService.saveAccessToken(accessToken, "");


	            //生成OAuth响应
	            oAuthRespOnse= OAuthASResponse
	                    .tokenResponse(HttpServletResponse.SC_OK)
	                    .setAccessToken(accessToken)	                   
	                    .setExpiresIn(String.valueOf( 3600L))
	                    .buildJSONMessage();

	            //根据OAuthResponse生成ResponseEntity
	            return new ResponseEntity(oAuthResponse.getBody(), HttpStatus.valueOf(oAuthResponse.getResponseStatus()));
				
			}
			else{
				return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, OAuthError.TokenResponse.INVALID_GRANT, ErrorConstants.ERROR_AUTH_CODE);
			}
			
			
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return ControllerHelper.getResponseEntity(HttpServletResponse.SC_BAD_REQUEST, ErrorConstants.ERROR_UNKNOW, e.getCause().getMessage());
		}		
	}

  

客户端主要有一下两个接口

/requestAuth: 重定向到拼接好的授权请求url

 

	@RequestMapping("/requestAuth")
	public ModelAndView requestAuth(@ModelAttribute("oauthParams") OauthParam oauthParams) {
		try {
			 OAuthClientRequest request = OAuthClientRequest
		                .authorizationLocation(oauthParams.getAuthzEndpoint())
		                .setClientId(oauthParams.getClientId())
		                .setRedirectURI(oauthParams.getRedirectUri())
		                .setResponseType(ResponseType.CODE.toString())
		                .setScope(oauthParams.getScope())
		                .setState(oauthParams.getState())
		                .buildQueryMessage();

		     return new ModelAndView(new RedirectView(request.getLocationUri()));
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			return null;
		}
	}

  

/redirect:获取授权码后,处理授权码的重定向地址。

 

  OAuthAuthzResponse oar = null;
  oar = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
  String code = oar.getCode();//获取授权码
  OAuthClientRequest request2 =OAuthClientRequest
	           		.tokenLocation(oauthParams.getTokenEndpoint())
	           		.setClientId(oauthParams.getClientId())
	           		.setClientSecret(oauthParams.getClientSecret())
	           		.setRedirectURI(oauthParams.getRedirectUri())
	           		.setCode(code)
	           		.setGrantType(GrantType.AUTHORIZATION_CODE)
	           		.buildBodyMessage();
	           
 OAuthClient client=new OAuthClient(new URLConnectionClient());
	           
 Class cl = OAuthJSONAccessTokenResponse.class;
	           //请求token
 OAuthAccessTokenResponse oauthRespOnse=client.accessToken(request2,cl);
 String token=oauthResponse.getAccessToken();//获取token

 源码地址:https://github.com/huanglin101/springboot_oltu_oauth2.git


推荐阅读
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • 基于移动平台的会展导游系统APP设计与实现的技术介绍与需求分析
    本文介绍了基于移动平台的会展导游系统APP的设计与实现过程。首先,对会展经济和移动互联网的概念进行了简要介绍,并阐述了将会展引入移动互联网的意义。接着,对基础技术进行了介绍,包括百度云开发环境、安卓系统和近场通讯技术。然后,进行了用户需求分析和系统需求分析,并提出了系统界面运行流畅和第三方授权等需求。最后,对系统的概要设计进行了详细阐述,包括系统前端设计和交互与原型设计。本文对基于移动平台的会展导游系统APP的设计与实现提供了技术支持和需求分析。 ... [详细]
author-avatar
醣荳_448
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有