SpringBoot實戰電商專案mall(20k+star)地址:github.com/macrozheng/…
摘要
Spring Cloud Security 為構建安全的SpringBoot應用提供了一系列解決方案,結合Oauth2可以實現單點登入功能,本文將對其單點登入用法進行詳細介紹。
單點登入簡介
單點登入(Single Sign On)指的是當有多個系統需要登入時,使用者只需登入一個系統,就可以訪問其他需要登入的系統而無需登入。
建立oauth2-client模組
這裡我們建立一個oauth2-client服務作為需要登入的客戶端服務,使用上一節中的oauth2-jwt-server服務作為認證服務,當我們在oauth2-jwt-server服務上登入以後,就可以直接訪問oauth2-client需要登入的介面,來演示下單點登入功能。
- 在pom.xml中新增相關依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
複製程式碼
- 在application.yml中進行配置:
server:
port: 9501
servlet:
session:
cookie:
name: OAUTH2-CLIENT-SESSIONID #防止Cookie衝突,衝突會導致登入驗證不通過
oauth2-server-url: http://localhost:9401
spring:
application:
name: oauth2-client
security:
oauth2: #與oauth2-server對應的配置
client:
client-id: admin
client-secret: admin123456
user-authorization-uri: ${oauth2-server-url}/oauth/authorize
access-token-uri: ${oauth2-server-url}/oauth/token
resource:
jwt:
key-uri: ${oauth2-server-url}/oauth/token_key
複製程式碼
- 在啟動類上新增@EnableOAuth2Sso註解來啟用單點登入功能:
@EnableOAuth2Sso
@SpringBootApplication
public class Oauth2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(Oauth2ClientApplication.class, args);
}
}
複製程式碼
- 新增介面用於獲取當前登入使用者資訊:
/**
* Created by macro on 2019/9/30.
*/
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/getCurrentUser")
public Object getCurrentUser(Authentication authentication) {
return authentication;
}
}
複製程式碼
修改認證伺服器配置
修改oauth2-jwt-server模組中的AuthorizationServerConfig類,將繫結的跳轉路徑為http://localhost:9501/login,並新增獲取祕鑰時的身份認證。
/**
* 認證伺服器配置
* Created by macro on 2019/9/30.
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
//以上省略一堆程式碼...
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("admin")
.secret(passwordEncoder.encode("admin123456"))
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(864000)
// .redirectUris("http://www.baidu.com")
.redirectUris("http://localhost:9501/login") //單點登入時配置
.scopes("all")
.authorizedGrantTypes("authorization_code","password","refresh_token");
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.tokenKeyAccess("isAuthenticated()"); // 獲取金鑰需要身份認證,使用單點登入時必須配置
}
}
複製程式碼
網頁單點登入演示
-
啟動oauth2-client服務和oauth2-jwt-server服務;
-
訪問客戶端需要授權的介面http://localhost:9501/user/getCurrentUser會跳轉到授權服務的登入介面;
- 進行登入操作後跳轉到授權頁面;
- 授權後會跳轉到原來需要許可權的介面地址,展示登入使用者資訊;
- 如果需要跳過授權操作進行自動授權可以新增
autoApprove(true)
配置:
/**
* 認證伺服器配置
* Created by macro on 2019/9/30.
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
//以上省略一堆程式碼...
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("admin")
.secret(passwordEncoder.encode("admin123456"))
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(864000)
// .redirectUris("http://www.baidu.com")
.redirectUris("http://localhost:9501/login") //單點登入時配置
.autoApprove(true) //自動授權配置
.scopes("all")
.authorizedGrantTypes("authorization_code","password","refresh_token");
}
}
複製程式碼
呼叫介面單點登入演示
這裡我們使用Postman來演示下如何使用正確的方式呼叫需要登入的客戶端介面。
-
訪問客戶端需要登入的介面:http://localhost:9501/user/getCurrentUser
-
使用Oauth2認證方式獲取訪問令牌:
- 輸入獲取訪問令牌的相關資訊,點選請求令牌:
- 此時會跳轉到認證伺服器進行登入操作:
- 登入成功後使用獲取到的令牌:
- 最後請求介面可以獲取到如下資訊:
{
"authorities": [
{
"authority": "admin"
}
],
"details": {
"remoteAddress": "0:0:0:0:0:0:0:1",
"sessionId": "63BB793E35383B2FFC608333B3BF4988",
"tokenValue": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJtYWNybyIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE1NzI2OTAxNzUsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjIwN2U5MTQzLTVjNTUtNDhkMS1iZmU3LTgwMzUyZTQ3Y2QyZCIsImNsaWVudF9pZCI6ImFkbWluIiwiZW5oYW5jZSI6ImVuaGFuY2UgaW5mbyJ9.xf3cBu9yCm0sME0j3UcP53FwF4tJVJC5aJbEj_Y2XcU",
"tokenType": "bearer",
"decodedDetails": null
},
"authenticated": true,
"userAuthentication": {
"authorities": [
{
"authority": "admin"
}
],
"details": null,
"authenticated": true,
"principal": "macro",
"credentials": "N/A",
"name": "macro"
},
"clientOnly": false,
"oauth2Request": {
"clientId": "admin",
"scope": [
"all"
],
"requestParameters": {
"client_id": "admin"
},
"resourceIds": [],
"authorities": [],
"approved": true,
"refresh": false,
"redirectUri": null,
"responseTypes": [],
"extensions": {},
"grantType": null,
"refreshTokenRequest": null
},
"principal": "macro",
"credentials": "",
"name": "macro"
}
複製程式碼
oauth2-client新增許可權校驗
- 新增配置開啟基於方法的許可權校驗:
/**
* 在介面上配置許可權時使用
* Created by macro on 2019/10/11.
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(101)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
複製程式碼
- 在UserController中新增需要admin許可權的介面:
/**
* Created by macro on 2019/9/30.
*/
@RestController
@RequestMapping("/user")
public class UserController {
@PreAuthorize("hasAuthority('admin')")
@GetMapping("/auth/admin")
public Object adminAuth() {
return "Has admin auth!";
}
}
複製程式碼
- 訪問需要admin許可權的介面:http://localhost:9501/user/auth/admin
- 使用沒有
admin
許可權的帳號,比如andy:123456
獲取令牌後訪問該介面,會發現沒有許可權訪問。
使用到的模組
springcloud-learning
├── oauth2-jwt-server -- 使用jwt的oauth2認證測試服務
└── oauth2-client -- 單點登入的oauth2客戶端服務
複製程式碼
專案原始碼地址
公眾號
mall專案全套學習教程連載中,關注公眾號第一時間獲取。