Apache的Oltu就是實現了OAuth的框架java
參考文章:web
http://jinnianshilongnian.iteye.com/blog/2038646spring
https://blog.csdn.net/jing12062011/article/details/78147306apache
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.linkedbear</groupId> <artifactId>OAuth-Demo</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <oauth2.version>1.0.2</oauth2.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- OAuth2協議的框架 --> <dependency> <groupId>org.apache.oltu.oauth2</groupId> <artifactId>org.apache.oltu.oauth2.client</artifactId> <version>${oauth2.version}</version> </dependency> <dependency> <groupId>org.apache.oltu.oauth2</groupId> <artifactId>org.apache.oltu.oauth2.common</artifactId> <version>${oauth2.version}</version> </dependency> <dependency> <groupId>org.apache.oltu.oauth2</groupId> <artifactId>org.apache.oltu.oauth2.authzserver</artifactId> <version>${oauth2.version}</version> </dependency> <dependency> <groupId>org.apache.oltu.oauth2</groupId> <artifactId>org.apache.oltu.oauth2.resourceserver</artifactId> <version>${oauth2.version}</version> </dependency> <!-- 熱部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
|
/** * 服務消費方Controller層 * @Title OauthClientController * @author LinkedBear * @Time 2018年8月1日 下午2:10:14 */ @Controller public class OauthClientController { //第一步:服務消費方要向用戶申請受權碼 @RequestMapping("/applyCode") public String applyCode(HttpServletRequest request) { System.out.println("----------第一步:服務消費方要向用戶申請受權碼-----------"); //第二步的跳轉url(請求Code) String accessCodeUrl = "getAuthorization"; //必填,且固定爲code String responseType = "code"; //必填 String clientId = "client"; //第三步要訪問的url String redirectUri = "http://localhost:8080/applyToken"; //建立OAuth客戶端對象 //OAuthClient client = new OAuthClient(new URLConnectionClient()); //構建OAuth請求 String locationUri = ""; try { OAuthClientRequest oauthRequest = AuthClientRequest.authorizationLocation(accessCodeUrl) .setRedirectURI(redirectUri) .setClientId(clientId) .setResponseType(responseType) .buildQueryMessage(); locationUri = oauthRequest.getLocationUri(); System.out.println("第一步重定向地址:" + locationUri); } catch (Exception e) { e.printStackTrace(); } //重定向 return "redirect:http://localhost:8080/" + locationUri; } //第三步:服務消費方要向認證受權服務器發起請求,攜帶本機ID和受權碼 @RequestMapping("/applyToken") public String applyToken(HttpServletRequest request) { System.out.println("----------第三步:服務消費方要向認證受權服務器發起請求,攜帶本機ID和受權碼----------"); //第四步的跳轉url(請求Token) //關鍵:這裏是要發請求返回json,故不是重定向,在下面沒有url拼接,只能在這裏寫全 String accessTokenUrl = "http://localhost:8080/getToken"; String clientId = "client"; //用於識別客戶端的字段 String clientSecurt = "clientSecurt"; //第五步要訪問的url String redirectUri = "http://localhost:8080/callbackCode"; String code = request.getParameter("code"); System.out.println("用戶返回的受權碼:" + code); //建立OAuth客戶端對象 OAuthClient client = new OAuthClient(new URLConnectionClient()); //構建OAuth請求 String locationUri = ""; try { //這裏的請求由於攜帶了受權碼,而且是請求訪問Token,故調用方法會不一樣 OAuthClientRequest oauthCodeRequest = OAuthClientRequest.tokenLocation(accessTokenUrl) .setGrantType(GrantType.AUTHORIZATION_CODE) .setRedirectURI(redirectUri) .setClientId(clientId) .setClientSecret(clientSecurt) .setCode(code) .buildQueryMessage(); locationUri = oauthCodeRequest.getLocationUri(); System.out.println("第三步重定向地址:" + locationUri); //發送請求,並獲得響應 OAuthJSONAccessTokenResponse tokenResponse = client.accessToken(oauthCodeRequest, HttpMethod.POST); //取訪問Token String token = tokenResponse.getAccessToken(); System.out.println("獲得訪問Token:" + token); //重定向 return "redirect:http://localhost:8080/applyResource?accessToken=" + token; } catch (Exception e) { e.printStackTrace(); return null; } } //第五步:服務消費方持Token訪問請求服務提供方 @RequestMapping("/applyResource") @ResponseBody public Map<String, Object> applyResource(String accessToken) { System.out.println("----------第五步:服務消費方持Token訪問請求服務提供方-----------"); //真正要請求的資源地址 String realResourceUrl = "http://localhost:8080/getResource"; //建立OAuth客戶端對象 OAuthClient client = new OAuthClient(new URLConnectionClient()); try { //構建真正的資源訪問請求,要附帶Token過去 OAuthClientRequest oauthTokenRequest = new OAuthBearerClientRequest(realResourceUrl) .setAccessToken(accessToken) .buildQueryMessage(); System.out.println("準備向服務提供方發送請求。。。"); //請求資源 OAuthResourceResponse resourceResponse = client.resource(oauthTokenRequest, HttpMethod.GET, OAuthResourceResponse.class); String resource = resourceResponse.getBody(); System.out.println("獲得請求的資源" + resource); return JSONUtils.parseJSON(resource); } catch (Exception e) { return null; } } }
/** * 用戶 Controller層 * @Title OauthUserController * @author LinkedBear * @Time 2018年8月1日 下午2:30:29 */ @Controller public class OauthUserController { public static final String AUTHORIZATION_CODE = "123"; //第二步:用戶收到服務消費方的請求後校驗,作出響應,返回受權碼 @SuppressWarnings("unused") @RequestMapping("/getAuthorization") public Object getAuthorization(HttpServletRequest request) { System.out.println("----------第二步:用戶收到服務消費方的請求後校驗,作出響應-----------"); try { //構建OAuth受權請求 OAuthAuthzRequest authzRequest = new OAuthAuthzRequest(request); //駁回空客戶端請求 if (StringUtils.isEmpty(authzRequest.getClientId())) { return null; } //取responseType,受權碼模式的值固定位"code" String responseType = authzRequest.getResponseType(); //構建OAuth響應,此處必須爲302重定向 OAuthAuthorizationResponseBuilder responseBuilder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND); //設置受權碼 responseBuilder.setCode(AUTHORIZATION_CODE); //獲得服務消費方的重定向地址,並構建OAuth響應 String redirectUri = authzRequest.getRedirectURI(); OAuthResponse oauthResponse = responseBuilder.location(redirectUri) .buildQueryMessage(); //構建完畢後,獲得重定向的url String locationUri = oauthResponse.getLocationUri(); System.out.println("第二步重定向地址:" + locationUri); return "redirect:" + locationUri; } catch (Exception e) { e.printStackTrace(); return null; } } }
/** * 認證受權服務器Controller層 * @Title OauthAuthenticationController * @author LinkedBear * @Time 2018年8月1日 下午2:10:57 */ @Controller public class OauthAuthenticationController { //第四步:訪問受權服務器接收服務消費方的請求,校驗並授予訪問Token和更新Token @PostMapping("/getToken") public ResponseEntity<Object> getToken(HttpServletRequest request) { System.out.println("----------第四步:訪問受權服務器接收服務消費方的請求,校驗並授予訪問Token和更新Token-----------"); try { //構建OAuth受權請求,此處已有Code OAuthTokenRequest authzTokenRequest = new OAuthTokenRequest(request); //獲取受權碼 String code = authzTokenRequest.getCode(); //受權碼不匹配,直接駁回 if (!OauthUserController.AUTHORIZATION_CODE.equals(code)) { return null; } //生成Token OAuthIssuerImpl tokenCreater = new OAuthIssuerImpl(new MD5Generator()); String token = tokenCreater.accessToken(); System.out.println("生成Token:" + token); //構建OAuth響應 OAuthResponse oauthResponse = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK) .setAccessToken(token) .setTokenType(TokenType.BEARER.name()) .buildJSONMessage(); //返回的數據是一組json return new ResponseEntity<Object>(oauthResponse.getBody(), HttpStatus.valueOf(oauthResponse.getResponseStatus())); } catch (Exception e) { e.printStackTrace(); return null; } } }
/** * 服務提供方Controller層 * @Title OauthServerController * @author LinkedBear * @Time 2018年8月1日 下午2:09:35 */ @Controller public class OauthServerController { //第六步:服務提供方驗證Token,返回資源 @RequestMapping("/getResource") @ResponseBody public ResponseEntity<Map<String, Object>> getResource(HttpServletRequest request) { System.out.println("----------第六步:服務提供方驗證Token,返回資源-----------"); try { //最後一步取的是資源,因此構建的請求也不一樣了,並且要附帶一個參數 OAuthAccessResourceRequest resourceRequest = new OAuthAccessResourceRequest(request, ParameterStyle.QUERY); String token = resourceRequest.getAccessToken(); //這裏還須要驗證Token。。。 System.out.println("未校驗Token。。。" + token); Map<String, Object> map = new HashMap<>(); map.put("data", Math.random()); map.put("creater", "LinkedBear"); return new ResponseEntity<Map<String, Object>>(map, HttpStatus.OK); } catch (Exception e) { e.printStackTrace(); return null; } } }
----------第一步:服務消費方要向用戶申請受權碼----------- 第一步重定向地址:getAuthorization?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2FapplyToken&client_id=client ----------第二步:用戶收到服務消費方的請求後校驗,作出響應----------- 第二步重定向地址:http://localhost:8080/applyToken?code=123 ----------第三步:服務消費方要向認證受權服務器發起請求,攜帶本機ID和受權碼----------- 用戶返回的受權碼:123 第三步重定向地址:http://localhost:8080/getToken?code=123&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2FcallbackCode&client_secret=clientSecurt&client_id=client ----------第四步:訪問受權服務器接收服務消費方的請求,校驗並授予訪問Token和更新Token----------- 生成Token:b9bbc794d09cac19f11951972fd7d5b1 獲得訪問Token:b9bbc794d09cac19f11951972fd7d5b1 ----------第五步:服務消費方持Token訪問請求服務提供方----------- 準備向服務提供方發送請求。。。 ----------第六步:服務提供方驗證Token,返回資源----------- 未校驗Token。。。b9bbc794d09cac19f11951972fd7d5b1 獲得請求的資源{"data":0.08976006535502468,"creater":"LinkedBear"}