SpringCloud微服務實戰系列(二十)Ouath2在真實場景中的應用之客戶端接入(第二種寫法)
一、概述
在《SpringCloud微服務實戰系列(十七)Ouath2在真實場景中的應用之資源服務器》]中
已經介紹了資源服務器是如何搭建的。
在《SpringCloud微服務實戰系列(十八)Ouath2在真實場景中的應用之授權服務器》]中
已經介紹了授權服務器是如何搭建的。
在《SpringCloud微服務實戰系列(十九)Ouath2在真實場景中的應用之客戶端接入(第一種寫法)》]中
已經介紹了授權服務器是如何搭建的。
本篇就是對Oauth2的實際應用方法的客戶端接入方式的另外一種方法進行介紹。這種方法跟第一種除配置外的區別是:
- 用戶信息接口需要手動調用。
- Nginx配置無所謂,可以在配置中指明跳轉地址。
首發地址:SpringCloud微服務實戰系列(二十)Ouath2在真實場景中的應用之客戶端接入(第二種寫法)
如果大家正在尋找一個java的學習環境,或者在開發中遇到困難,可以加入我們的java學習圈,點擊即可加入,共同學習,節約學習時間,減少很多在學習中遇到的難題。
在Spring Oauth2中,Oauth2的使用過程中將角色分爲三種:ResourceServer,AuthorizationServer,OauthClient.
由於篇幅較大,這裏將Oauth2的搭建分成三個部分。本篇介紹OauthClient的另外一種寫法。
這種方式是基於spring-security-oauth2-autoconfigure的自動化配置。在spring-security-oauth2-boot官方文檔可以找到這種配置方法。https://docs.spring.io/spring-security-oauth2-boot/docs/current/reference/htmlsingle/#boot-features-security-oauth2-resource-server
代碼可以在https://www.pomit.cn/java/spring/springcloud.html中的Oauth2相關中的組件下載即可。
二、客戶端接入
客戶端接入是一個複雜的過程,按照spring-security-oauth2-boot官方文檔的指引,我這裏把完整的流程寫出來。
下面講述下這個過程是怎樣的。
2.1 引入依賴
需要引入spring-boot-starter-web、spring-cloud-starter-security、spring-security-oauth2和spring-security-oauth2-autoconfigure相關jar包.
依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${security.oauth2.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${security.oauth2.boot.version}</version>
</dependency>
</dependencies>
這裏,security.oauth2.version版本是2.3.5.RELEASE,security.oauth2.boot.version是2.1.6.RELEASE。
2.2 配置文件
這裏使用yaml文件寫配置,配置文件application.yml:
application.yml:
server:
port: 8184
spring:
profiles:
active: loc
application:
name: oauthClient
這裏
- 應用名稱爲oauthClient
- 指定配置爲loc。
application-loc.yml:
env: loc
security:
oauth2:
resource:
userInfoUri: http://res.pomit.cn/api/userInfo
preferTokenInfo: false
client:
clientId: FeiTestClient
clientSecret: 123456
grantType: authorization_code
scope: trust
accessTokenUri: http://sso.pomit.cn/oauth/token
userAuthorizationUri: http://sso.pomit.cn/oauth/authorize
preEstablishedRedirectUri: http://ow.pomit.cn/token/login
useCurrentUri: false
sso:
login-path: /token/login
remote:
ipUrl: http://res.pomit.cn/api/ip
這裏配置的東西可能會讓你產生疑惑,下面一一講述:
- security.oauth2.client是客戶端的配置,其中,clientId和clientSecret是客戶端的密鑰,需要在授權服務器加上這個客戶端,accessTokenUri是token獲取地址,後綴基本上都是/oauth/token;userAuthorizationUri是授權地址,後綴基本上都是/oauth/authorize;,grantType是授權類型,preEstablishedRedirectUri是授權成功的回調地址,並通過security.oauth2.sso.login-path對這個地址進行捕獲來完成sso登錄。
- security.oauth2.resource是關於資源服務器的配置,是獲取用戶信息的地址。這個地址並不代表用戶信息就能自動獲取,需要用戶信息的時候還是要手動通過OAuth2RestTemplate去獲取。
- remote.ipUrl是我自定義的配置。
基本配置就是這樣了,如果中間出現問題,要多試幾次查找問題。
2.3 啓動
使用main直接啓動即可。無需其他配置。
OauthClientApplication:
package cn.pomit.springbootwork.oauthclient2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OauthClientApplication {
public static void main(String[] args) {
SpringApplication.run(OauthClientApplication.class, args);
}
}
2.4 安全控制配置
這個安全控制,只是普通的Spring Security的安全配置。
需要繼承WebSecurityConfigurerAdapter,並加上@EnableWebSecurity。
AccessSecurityConfiguration如下:
package cn.pomit.springbootwork.oauthclient2.config;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
@Configuration
@EnableOAuth2Sso
public class AccessSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
OAuth2RestTemplate template = new OAuth2RestTemplate(details, oauth2ClientContext);
return template;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().mvcMatchers("/test/**").permitAll()
.antMatchers("/").permitAll()
.antMatchers("/index.html").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/img/**").permitAll()
.anyRequest().authenticated();
}
}
其中,聲明瞭一個bean:OAuth2RestTemplate,用來獲取oauth2的一些信息使用。
2.5 測試web
這裏寫了三個web接口,來測試不用的訪問控制級別的返回信息。
OauthTestRest:
package cn.pomit.springbootwork.oauthclient2.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.pomit.springbootwork.oauthclient2.model.ResultModel;
@Controller
@RequestMapping("/")
public class OauthTestRest {
@ResponseBody
@RequestMapping(value = "/test/test", method = { RequestMethod.GET })
public ResultModel test() {
return ResultModel.ok("我就是test,客戶端2");
}
@RequestMapping(value = "/", method = { RequestMethod.GET })
public String index() {
return "/index.html";
}
@RequestMapping(value = "/logTo", method = { RequestMethod.GET })
public String logTo() {
return "/index.html";
}
}
OauthClientRest:
package cn.pomit.springbootwork.oauthclient2.web;
import java.security.Principal;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import cn.pomit.springbootwork.oauthclient2.model.IpModel;
import cn.pomit.springbootwork.oauthclient2.model.ResultModel;
import cn.pomit.springbootwork.oauthclient2.util.IPUtil;
@RestController
@RequestMapping("/api")
public class OauthClientRest {
@Value("${security.oauth2.resource.userInfoUri}")
private String userInfoUri;
@Autowired
private OAuth2RestTemplate oAuth2RestTemplate;
@RequestMapping(value = "/ip", method = { RequestMethod.GET })
public ResultModel ip(HttpServletRequest request) {
IpModel ipModel = new IpModel();
ipModel.setClientIpAddress(IPUtil.getIpAddr(request));
ipModel.setServerIpAddress(IPUtil.localIp());
return ResultModel.ok(ipModel);
}
@RequestMapping(value = "/test")
public ResultModel test(Principal principal) {
return ResultModel.ok(principal.getName());
}
@RequestMapping(value = "/userInfo")
public ResultModel userinfo(Principal principal) {
return oAuth2RestTemplate.getForObject(userInfoUri, ResultModel.class);
}
}
OauthRemoteRest:
package cn.pomit.springbootwork.oauthclient2.web;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import cn.pomit.springbootwork.oauthclient2.model.ResultModel;
@RestController
@RequestMapping("/remote")
public class OauthRemoteRest {
@Value("${remote.ipUrl}")
private String remoteIpUrl;
@Autowired
private OAuth2RestTemplate oAuth2RestTemplate;
@RequestMapping(value = "/ip", method = { RequestMethod.GET })
public ResultModel ip(HttpServletRequest request) {
ResultModel rm = oAuth2RestTemplate.getForObject(remoteIpUrl, ResultModel.class);
return rm;
}
}
2.6 過程中用到的其他實體和工具
IpModel :
package cn.pomit.springbootwork.oauthclient2.model;
public class IpModel {
private String clientIpAddress;
private String serverIpAddress;
public String getClientIpAddress() {
return clientIpAddress;
}
public void setClientIpAddress(String clientIpAddress) {
this.clientIpAddress = clientIpAddress;
}
public String getServerIpAddress() {
return serverIpAddress;
}
public void setServerIpAddress(String serverIpAddress) {
this.serverIpAddress = serverIpAddress;
}
}
IPUtil:
package cn.pomit.springbootwork.oauthclient2.util;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
public class IPUtil {
/**
* @Description: 獲取客戶端IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if (ip.equals("127.0.0.1")) {
// 根據網卡取本機配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (Exception e) {
e.printStackTrace();
}
ip = inet.getHostAddress();
}
}
// 多個代理的情況,第一個IP爲客戶端真實IP,多個IP按照','分割
if (ip != null && ip.length() > 15) {
if (ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
/**
* 獲取的是本地的IP地址
*
* @return
*/
public static String localIp() {
String result = "";
try {
InetAddress address = InetAddress.getLocalHost();
result = address.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return result;
}
}
ResultModel:
package cn.pomit.springbootwork.oauthclient2.model;
/**
* @author cff
*/
public class ResultModel {
private String errorCode;
private String message;
private Object data;
public ResultModel() {
}
public ResultModel(String errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
}
public ResultModel(String errorCode, String message, Object data) {
this.errorCode = errorCode;
this.message = message;
this.data = data;
}
public String getErrorCode() {
return errorCode;
}
public void set ErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static ResultModel ok(String testValue) {
ResultModel rm = new ResultModel();
rm.setData(testValue);
return rm;
}
}
三、測試過程
資源服務器:http://res.pomit.cn
授權服務器:http://sso.pomit.cn
客戶端:
服務器2:http://ow.pomit.cn
- 未授權時:
2. 點擊授權登錄:
3. 如果已經授權過,則不會出現授權頁面。否則出現授權登錄頁面:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RMWINiMH-1589852532694)(https://www.pomit.cn/upload/picture/20200512/305271141179648.jpg)]
4. 授權成功後,再點獲取信息:
四、微信OAUTH2授權過程
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-76GLei0i-1589852532697)(https://www.pomit.cn/upload/picture/20200512/305271523160320.jpg)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Z9oiPdy3-1589852532700)(https://www.pomit.cn/upload/picture/20200512/305271710093568.jpg)]
品茗IT-博客專題:https://www.pomit.cn/lecture.html彙總了Spring專題、Springboot專題、SpringCloud專題、web基礎配置專題。
快速構建項目
Spring項目快速開發工具:
喜歡這篇文章麼,喜歡就加入我們一起討論SpringCloud使用吧!
建SpringCloud項目工具](https://www.pomit.cn/java/spring/springcloud.html)
喜歡這篇文章麼,喜歡就加入我們一起討論SpringCloud使用吧!
[外鏈圖片轉存中…(img-JflslkRx-1589852532700)]