基於SpringBoot(2.1.9.RELEASE)、SpringCloud(Greenwich.SR3)
一、關於OAuth2
OAuth2是一種協議規範,spring-security-oauth2是對他的一種實現。其次,還有shiro實現,自己根據規範編寫代碼的實現方式。主流的qq,微信等第三方授權登錄方式都是基於oauth2實現的。
oauth2的認證方式有授權碼,簡單,賬戶密碼,客戶端等方式,具體請自行百度不做過多的闡述。
本文基於授權碼方式實現
oauth生態設計的範圍很大,可以說是一種解決方案,它有“第三方客戶端(web服務,APP服務)”、“用戶”、“認證服務器”、“資源服務器”等部分。認證流程如下圖:
- (A)用戶打開客戶端以後,客戶端要求用戶給予授權。
- (B)用戶同意給予客戶端授權。
- (C)客戶端使用上一步獲得的授權,向認證服務器申請令牌。
- (D)認證服務器對客戶端進行認證以後,確認無誤,同意發放令牌。
- (E)客戶端使用令牌,向資源服務器申請獲取資源。
- (F)資源服務器確認令牌無誤,同意向客戶端開放資源。
二、auth-server
1.創建auth-server工程,添加依賴。
springcloud-security已經封裝好了oauth2,所以只添加依賴spring-cloud-starter-oauth2,其他的依賴由於項目使用了Nacos和其他的組件,非必須
<!-- 依賴 -->
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- SpringCloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- Nacos -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
</dependencies>
2.創建WebSecurityConfig
認證之前需要先校驗用戶的賬戶密碼是否正確,所以我們先配置WebSecurityConfig攔截:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
BCryptPasswordEncoder passwordEncoder;
/**
* @Title: 配置內存用戶驗證
* @Param: [auth]
* @Return: void
* @Author: SunBin
* @Date: 2020/5/15 18:01
* @Throws:
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.inMemoryAuthentication()
.withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN")
.and()
.withUser("user").password(passwordEncoder.encode("123456")).roles("USER");
}
}
注意密碼用了BCryptPasswordEncoder進行加密,在springboot2.x中不加密會報錯
3.創建AuthConfig認證攔截處理
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
@Configuration
// 開啓認證服務
@EnableAuthorizationServer
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
/**
* @Title: 配置密碼加密,SpringBoot2.X必須
* @Param: []
* @Return: org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
* @Author: SunBin
* @Date: 2020/5/15 18:08
* @Throws:
*/
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
/**
* @Title: 基於內存的配置
* @Param: [clients]
* @Return: void
* @Author: SunBin
* @Date: 2020/5/15 18:13
* @Throws:
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception{
clients.inMemory()
// 客戶端ID
.withClient("client")
// 客戶端secret
.secret(passwordEncoder().encode("secret"))
// 授權類型:授權碼
.authorizedGrantTypes("authorization_code")
// 範圍
.scopes("app")
// 重定向地址
.redirectUris("http://127.0.0.1:8848/nacos/");
}
}
- 添加 @EnableAuthorizationServer註解開啓認證服務,注入加密用的BCryptPasswordEncoder實例。
- 配置需要認證的客戶端,client_id是需要認證的服務
- 客戶端的secret祕鑰需要加密
- authorizedGrantTypes授權方式指的是授權碼,簡單,客戶端,賬戶密碼等,這裏使用的是授權碼(authorization_code)
- 配置scopes範圍
- redirectUris重定向地址,就是授權後跳轉的地址。
4.配置文件:
bootstrap.yml
# 項目設置
spring:
profiles:
active: local # 默認激活文件
application:
name: auth-server
bootstrap-local.yml
# 設置服務
server:
port: 10410
# 項目設置
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
sentinel:
transport:
dashboard: localhost:8080
# 使用默認日誌slf4
logging:
level:
com.sunber: DEBUG # 可以按包顯示不同的級別
file: F://###LOGS/Sunber/Auth/AuthServer/out.log # 不指定目錄則輸出到當前項目下
5.啓動類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringCloudApplication
@EnableFeignClients(basePackages = {"com.sunber.**"})
@ComponentScan(basePackages= {"com.sunber"})
public class AuthServer {
public static void main(String[] args) {
SpringApplication.run(AuthServer.class, args);
}
}
6.啓動應用:
成功,我們用這個地址進行授權訪問:http://localhost:10410/oauth/authorize?client_id=client&response_type=code
成功後,跳轉到登錄頁面:
輸入賬戶:admin 密碼: 123456 點登錄
選擇approve點擊Authorize認證
這個code就是授權碼
postman用post方式獲取access_token,請求URL:http://client:secret@localhost:10410/oauth/token
- 這個client就是配置的client_id
- secret就是配置的secret
- 返回access_token