Spring Cloud Security:Oauth2實現單點登入

MacroZheng發表於2019-11-11

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()"); // 獲取金鑰需要身份認證,使用單點登入時必須配置
    }
}
複製程式碼

網頁單點登入演示

Spring Cloud Security:Oauth2實現單點登入

  • 進行登入操作後跳轉到授權頁面;

Spring Cloud Security:Oauth2實現單點登入

  • 授權後會跳轉到原來需要許可權的介面地址,展示登入使用者資訊;

Spring Cloud Security:Oauth2實現單點登入

  • 如果需要跳過授權操作進行自動授權可以新增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來演示下如何使用正確的方式呼叫需要登入的客戶端介面。

Spring Cloud Security:Oauth2實現單點登入

  • 輸入獲取訪問令牌的相關資訊,點選請求令牌:

Spring Cloud Security:Oauth2實現單點登入

  • 此時會跳轉到認證伺服器進行登入操作:

Spring Cloud Security:Oauth2實現單點登入

  • 登入成功後使用獲取到的令牌:

Spring Cloud Security: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!";
    }

}
複製程式碼

Spring Cloud Security:Oauth2實現單點登入

  • 使用沒有admin許可權的帳號,比如andy:123456獲取令牌後訪問該介面,會發現沒有許可權訪問。

Spring Cloud Security:Oauth2實現單點登入

使用到的模組

springcloud-learning
├── oauth2-jwt-server -- 使用jwt的oauth2認證測試服務
└── oauth2-client -- 單點登入的oauth2客戶端服務
複製程式碼

專案原始碼地址

github.com/macrozheng/…

公眾號

mall專案全套學習教程連載中,關注公眾號第一時間獲取。

公眾號圖片

相關文章