标签:去掉 提交 最新版 bind otn rac resource for and
OAuth 是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。目前,OAuth 的最新版本为 2.0。OAuth 允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提供者的数据。每一个令牌授权一个特定的网站(例如,视频编辑网站)在特定的时段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这样,OAuth 允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要分享他们的访问许可或他们数据的所有内容。
其中,用户授权有四种模式:
对应于步骤 (A) 和 (B) 的授权码请求如 图 1 所示。在步骤 (A) 中,客户端采用 application/x-www-form-urlencoded
格式向授权服务器发出一个请求,如 清单 1 所示。
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: server.example.com
该请求必须包含以下参数:
response_type
:必选项。该值必须设置为 code
。client_id
:必选项。客户端 ID。redirect_uri
:必选项。用于用户代理重定向。scope
:可选项。访问请求的范围。state
:可选项。保持请求和回调之间的状态在授权服务器验证请求后,服务器将一个 HTTP 重定向代码 302 响应发送回客户端。该响应还将在 http Location
标头中包括一个重定向 URI。在步骤 (B) 中,客户端必须将用户代理(通常是 Web 浏览器)重定向到此 URI。这种重定向 URI 通常是一个登录页面,资源所有者可以使用其凭据进行登录,并批准/撤销客户端的访问请求。
授权码响应该如 图 1 的步骤 (C) 中所示。如果资源所有者批准了访问请求,授权服务器会发出一个授权码。授权服务器将用户代理重定向到步骤 (A) 中作为请求的一部分的重定向 URI,并将授权码包含为重定向 URI 的查询组件的一部分,这里采用的是 application/x-www-form-urlencoded
格式。
URI 参数如下:
Code
:必选项。由授权服务器生成的授权码。该代码是临时的,并且必须在生成后很快过期。客户不得多次使用授权码。使用相同代码进行的任何进一步请求都应该被授权服务器撤销。授权码被绑定到客户端标识符和重定向 URI。State
:必选项。如果客户端的授权码请求中存在 state
参数,此参数必须设置为与从客户端接收的值完全相同。这对应于 图 1 中的步骤 (D)。客户端采用 application/x-www-form-urlencoded
格式向令牌端点(授权服务器)发出一个请求,如 清单 2 所示。
POST /token HTTP/1.1 Host: server.example.com Authorization:Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom&client_id=c342
访问令牌请求必须设置下列参数:
grant_type
:必选项。该值必须设置为 authorization_code
。client_id
:必选项。客户端 ID。client_secret
:可选项。密码,用于与授权服务器进行身份验证。code
:必选项。从服务器收到的授权码。redirect_uri
:必选项。在步骤 (A) 中发送的完全一样。授权服务器验证该代码和重定向 URI 是有效的。在存在机密性客户端的情况下,授权服务器也使用在其请求的主体或 Authorization 标头中传递的客户端凭据来对客户端进行身份验证。
这对应于 图 1 中的步骤 (E)。如果访问令牌请求是有效的,而且获得了授权,授权服务器会在一个访问令牌响应中返回访问令牌。成功的响应示例如 清单 3 所示。
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
这是一个可选步骤,如果客户端请求离线访问,并在访问令牌请求中提供一个 refresh_token
,则可以此阿勇此步骤。访问令牌是暂时性的,通常在一个小时后到期。访问令牌到期后,客户端需要重复身份验证过程,资源所有者需要进行登录,并提供授权,让客户可以再次发出访问令牌请求。
如果客户需要刷新访问令牌,而资源所有者没有位于浏览器上,无法进行登录和身份验证,则客户端可以采用离线访问。客户端可以在发出第一个授权码请求时请求离线访问(参见步骤 (A))。根据这项计划,除了访问令牌之外,授权服务器还会返回刷新令牌。刷新令牌是一个长寿令牌,不会过期,除非明确由资源所有者撤销。每当访问令牌到期时,客户端可以使用刷新令牌来重新生成一个访问令牌,资源所有者无需登录和授权访问请求。
客户端采用 application/x-www-form-urlencoded
格式向令牌端点(授权服务器)发出一个请求,如 清单 4 所示:
POST /token HTTP/1.1 Host: server.example.com Authorization:Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
请求参数的定义如下:
grant_type
:必选项。该值必须设置为 refresh_token
。refresh_token
:必选项。这是之前从访问令牌请求获得的令牌。scope
:可选项。访问请求的范围。如果请求成功,授权服务器将会返回一个新的访问令牌。成功的响应示例如 清单 5 所示。
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"Bearer", "expires_in":3600, "example_parameter":"example_value" }
在简化模式中,Authorization Code和Access Token都由授权服务器生成和验证,而最终只用到Access Token,这让Authorization Code显得无足轻重。因此,授权码简化模式,去掉了Authorization Code的申请流程,从而通过User-Agent(Browser)直接申请Access Token。
该模式下,需要用户将自身的account ID和password交由client,client将使用它们来申请access token,整个过程会将用户信息暴露。因此,除非client十分可靠(例如硬件设备,系统APP),否则,不建议使用该模式。
(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
(C)认证服务器确认无误后,向客户端提供访问令牌。
Request:
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=password&username=johndoe&password=A3ddj3w
Response:
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
该模式下,并不存在对个体用户授权的行为,被授权的主体为client。因此,该模式可用于对某类用户进行集体授权。
(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。
(B)认证服务器确认无误后,向客户端提供访问令牌。
Request:
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=client_credentials
Response:
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "example_parameter":"example_value" }
需要加入的jar包:org.apache.oltu.oauth2.client-1.0.1.jar
package authclient; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.oltu.oauth2.client.OAuthClient; import org.apache.oltu.oauth2.client.URLConnectionClient; import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest; import org.apache.oltu.oauth2.client.request.OAuthClientRequest; import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse; import org.apache.oltu.oauth2.client.response.OAuthResourceResponse; import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.types.GrantType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @RequestMapping("/server") @Controller public class ClientController { String clientId = null; String clientSecret = null; String accessTokenUrl = null; String userInfoUrl = null; String redirectUrl = null; String response_type = null; String code= null; //提交申请code的请求 @RequestMapping(value="/requestServerCode",produces="application/json;charset=UTF-8") public String requestServerFirst(HttpServletRequest request, HttpServletResponse response, RedirectAttributes attr) throws OAuthProblemException{ clientId = "clientId"; clientSecret = "clientSecret"; accessTokenUrl = "responseCode"; redirectUrl = "http://localhost:8080/OAuthClientTest/server/callbackCode"; response_type = "code"; System.out.println("================"); OAuthClient oAuthClient =new OAuthClient(new URLConnectionClient()); String requestUrl = null; try { //构建oauth的请求。设置请求服务地址(accessTokenUrl)、clientId、response_type、redirectUrl OAuthClientRequest accessTokenRequest = OAuthClientRequest .authorizationLocation(accessTokenUrl) .setResponseType(response_type) .setClientId(clientId) .setRedirectURI(redirectUrl) .buildQueryMessage(); requestUrl = accessTokenRequest.getLocationUri(); System.out.println(requestUrl); } catch (OAuthSystemException e) { e.printStackTrace(); } return "redirect:http://localhost:8080/OAuthServerTest/"+requestUrl ; } //接受客户端返回的code,提交申请access token的请求,对应上图中的步骤三 @RequestMapping(value="/callbackCode",produces="application/json;charset=UTF-8") public Object toLogin(HttpServletRequest request) throws OAuthProblemException{ clientId = "clientId"; clientSecret = "clientSecret"; accessTokenUrl="http://localhost:8080/OAuthServerTest/responseAccessToken"; userInfoUrl = "userInfoUrl"; redirectUrl = "http://localhost:8080/OAuthClientTest/server/accessToken"; HttpServletRequest httpRequest = (HttpServletRequest) request; OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); System.out.println("--------客户端端/callbackCode-----------------"); try { OAuthClientRequest accessTokenRequest = OAuthClientRequest .tokenLocation(accessTokenUrl) .setGrantType(GrantType.AUTHORIZATION_CODE) .setClientId(clientId) .setClientSecret(clientSecret) .setCode(httpRequest.getParameter("code")) .setRedirectURI(redirectUrl) .buildQueryMessage(); //去服务端请求access token,并返回响应 OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST); //获取服务端返回过来的access token String accessToken = oAuthResponse.getAccessToken(); //查看access token是否过期 Long expiresIn = oAuthResponse.getExpiresIn(); return "redirect:http://localhost:8080/OAuthClientTest/server/accessToken?accessToken="+accessToken; } catch (OAuthSystemException e) { e.printStackTrace(); } return null; } //接受服务端传回来的access token,由此token去请求服务端的资源(用户信息等),对应上图中的步骤五 @RequestMapping(value="/accessToken",produces="application/json;charset=UTF-8") public ModelAndView accessToken(String accessToken) { userInfoUrl = "http://localhost:8080/OAuthServerTest/userInfo"; OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); System.out.println("--------客户端端/accessToken-----------------"); try { OAuthClientRequest userInfoRequest = new OAuthBearerClientRequest(userInfoUrl) .setAccessToken(accessToken).buildQueryMessage(); OAuthResourceResponse resourceResponse = oAuthClient.resource(userInfoRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class); String username = resourceResponse.getBody(); System.out.println("--------客户端端/accessToken-----------------"+username); ModelAndView modelAndView = new ModelAndView("usernamePage"); modelAndView.addObject("username", username); return modelAndView; } catch (OAuthSystemException e) { e.printStackTrace(); } catch (OAuthProblemException e) { e.printStackTrace(); } return null; } }
需要加入的jar包:org.apache.oltu.oauth2.authzserver-1.0.1.jar和org.apache.oltu.oauth2.resourceserver-1.0.1.jar
向客户端返回授权码code的controller方法
package authserver; import java.net.URI; import java.net.URISyntaxException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest; import org.apache.oltu.oauth2.as.response.OAuthASResponse; import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.OAuthResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import service.UserService; @Controller public class ServerController{ @Autowired private UserService userService; //向客户端返回授权许可码 code @RequestMapping(value="/responseCode",produces="application/json;charset=UTF-8") public Object toShowUser(Model model, HttpServletRequest request){ System.out.println("----------服务端/responseCode------------"); try { //构建OAuth授权请求 OAuthAuthzRequest oauthRequest =new OAuthAuthzRequest(request); /*oauthRequest.getClientId(); oauthRequest.getResponseType(); oauthRequest.getRedirectURI(); System.out.println(oauthRequest.getClientId()); System.out.println(oauthRequest.getResponseType()); System.out.println(oauthRequest.getRedirectURI());*/ if(oauthRequest.getClientId()!=null&&oauthRequest.getClientId()!="") { //设置授权码 String authorizationCode ="authorizationCode"; //利用oauth授权请求设置responseType,目前仅支持CODE,另外还有TOKEN String responseType =oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE); //进行OAuth响应构建 OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND); //设置授权码 builder.setCode(authorizationCode); //得到到客户端重定向地址 String redirectURI =oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI); //构建响应 final OAuthResponse response =builder.location(redirectURI).buildQueryMessage(); System.out.println("服务端/responseCode内,返回的回调路径:"+response.getLocationUri()); System.out.println("----------服务端/responseCode--------------------"); String responceUri =response.getLocationUri(); //根据OAuthResponse返回ResponseEntity响应 HttpHeaders headers =new HttpHeaders(); try { headers.setLocation(new URI(response.getLocationUri())); } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); } return"redirect:"+responceUri; } } catch (OAuthSystemException e) { e.printStackTrace(); } catch (OAuthProblemException e) { e.printStackTrace(); } System.out.println("----------服务端/responseCode------------------"); return null; } }
向客户端返回资源访问令牌accesstoken的controller方法
package authserver; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.oltu.oauth2.as.issuer.MD5Generator; import org.apache.oltu.oauth2.as.issuer.OAuthIssuer; import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl; import org.apache.oltu.oauth2.as.request.OAuthTokenRequest; import org.apache.oltu.oauth2.as.response.OAuthASResponse; import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.OAuthResponse; import org.springframework.http.HttpEntity; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import net.sf.json.JSONObject; @Controller public class AccessTokenController { //获取客户端的code码,向客户端返回access token @RequestMapping(value="/responseAccessToken",method = RequestMethod.POST,produces="application/json;charset=UTF-8") public HttpEntity token(HttpServletRequest request){ System.out.println("--------服务端/responseAccessToken----------开始-----------"); OAuthIssuer oauthIssuerImpl=null; OAuthResponse response=null; //构建OAuth请求 try { OAuthTokenRequest oauthRequest =new OAuthTokenRequest(request); String authCode =oauthRequest.getParam(OAuth.OAUTH_CODE); String clientSecret = oauthRequest.getClientSecret(); if(clientSecret!=null||clientSecret!=""){ //生成Access Token oauthIssuerImpl =new OAuthIssuerImpl(new MD5Generator()); final String accessToken =oauthIssuerImpl.accessToken(); System.out.println(accessToken); System.out.println("--oooo---"+authCode+"======"+clientSecret); //生成OAuth响应 response = OAuthASResponse .tokenResponse(HttpServletResponse.SC_OK) .setAccessToken(accessToken) .buildJSONMessage(); } // String access_token = response.getBody().toString(); // String value = access_token.replace("access_token=", ""); // JSONObject jsonObject = new JSONObject(); // jsonObject.put("access_token", value); System.out.println("--------服务端/responseAccessToken-----"); //根据OAuthResponse生成ResponseEntity return new ResponseEntity(response.getBody(), HttpStatus.valueOf(response.getResponseStatus())); } catch (OAuthSystemException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (OAuthProblemException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("--------服务端/responseAccessToken---------------------"); return null; } }
向客户端返回请求资源(username)的controller方法
package authserver; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.OAuthResponse; import org.apache.oltu.oauth2.common.message.types.ParameterStyle; import org.apache.oltu.oauth2.common.utils.OAuthUtils; import org.apache.oltu.oauth2.rs.request.OAuthAccessResourceRequest; import org.apache.oltu.oauth2.rs.response.OAuthRSResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import domain.User; import service.UserService; @Controller public class UserInfoController { @Autowired private UserService userService; @RequestMapping(value="/userInfo",produces="application/json;charset=UTF-8") public HttpEntity userInfo(HttpServletRequest request)throws OAuthSystemException{ System.out.println("-----------服务端/userInfo---------"); try { //获取客户端传来的OAuth资源请求 OAuthAccessResourceRequest oauthRequest = new OAuthAccessResourceRequest(request, ParameterStyle.QUERY); //获取Access Token String accessToken =oauthRequest.getAccessToken(); System.out.println("accessToken"); //验证Access Token /*if (accessToken==null||accessToken=="") { // 如果不存在/过期了,返回未验证错误,需重新验证 OAuthResponse oauthResponse = OAuthRSResponse .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .setError(OAuthError.ResourceResponse.INVALID_TOKEN) .buildHeaderMessage(); HttpHeaders headers = new HttpHeaders(); headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED); } */ //返回用户名 User user=userService.selectByPrimaryKey(1); String username = accessToken+"---"+Math.random()+"----"+"youzhongmin"; System.out.println(username); System.out.println("服务端/userInfo::::::ppp"); System.out.println("-----------服务端/userInfo----------------------------------------------------------"); return new ResponseEntity(username, HttpStatus.OK); } catch (OAuthProblemException e) { // TODO Auto-generated catch block e.printStackTrace(); //检查是否设置了错误码 String errorCode =e.getError(); if (OAuthUtils.isEmpty(errorCode)) { OAuthResponse oauthResponse = OAuthRSResponse .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .buildHeaderMessage(); HttpHeaders headers =new HttpHeaders(); headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); return new ResponseEntity(headers, HttpStatus.UNAUTHORIZED); } OAuthResponse oauthResponse = OAuthRSResponse .errorResponse(HttpServletResponse.SC_UNAUTHORIZED) .setError(e.getError()) .setErrorDescription(e.getDescription()) .setErrorUri(e.getUri()) .buildHeaderMessage(); HttpHeaders headers =new HttpHeaders(); headers.add(OAuth.HeaderType.WWW_AUTHENTICATE, oauthResponse.getHeader(OAuth.HeaderType.WWW_AUTHENTICATE)); System.out.println("-----------服务端/userInfo------------------------------------"); return new ResponseEntity(HttpStatus.BAD_REQUEST); } } }
标签:去掉 提交 最新版 bind otn rac resource for and
原文地址:https://www.cnblogs.com/youzhongmin/p/9194148.html