zoukankan      html  css  js  c++  java
  • oauth2 学习(一)-使用Apache oltu实现oauth2的授权服务器

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

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

     

      比较之后发现资料相对较多的是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<? extends OAuthAccessTokenResponse> cl = OAuthJSONAccessTokenResponse.class;
    	           //请求token
     OAuthAccessTokenResponse oauthResponse=client.accessToken(request2,cl);
     String token=oauthResponse.getAccessToken();//获取token
    

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

  • 相关阅读:
    centos7grub2 引导win10
    必测的支付漏洞(一)——使用fiddler篡改支付金额
    使用Fiddler进行IOS APP的HTTP抓包
    Fiddler实现手机抓包——小白入门
    信息收集工具recon-ng详细使用教程
    Chrome浏览器扩展开发系列之一:初识Google Chrome扩展
    Dear Project Manager, I Hate You
    敏捷中的沟通与故事点
    项目经理与敏捷开发
    C#中使用反射获取结构体实例
  • 原文地址:https://www.cnblogs.com/huanglin101/p/8334208.html
Copyright © 2011-2022 走看看