(此處省略2000字廢話),第一次寫博客,直接進入正題了。
從初學者的角度來看,初次使用spring-boot和spring-security-oauth2整合,第一步自然是搭建一個“Hello World”先跑起來。那么二話不說,先來一個spring-boot的“Hello World”。
本小菜使用idea+maven搭建項目,假設已經有了一個基本的maven-archetype-web架構,如圖:
關於架構的目錄結構,每個人都有自己的看法,小菜的設計思路是client發送請求,按照“web”-“service”-“dao”的順序與數據庫交互,生成“po”。框架的配置放在“config”中,一些dao層或者其他層的封裝放在“common”中,String、Excel等工具類放在util中,“api”是提供給外部訪問的接口層,可以調用“service”,也可以調用“web”。
一、搭建一個spring-boot的web項目。
1、添加jar包:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
spring-boot基於spring-mvc,因此還需要
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如圖:
依賴成功后,在External Libraies中會顯示需要的jar包,接下來的快速簡單web開發就是靠他們了。
2、spring-boot啟動類
主要是配置@SpringBootApplication,大概意思就是告訴spring-boot程序入口在這里。
3、"web"訪問層Controller類
4、啟動spring-boot
可以直接從App.class的main方法run或者debug啟動,也可以使用mvn spring-boot:run命令啟動
輸入http://localhost:8080/home,測試結果:
二、spring-security-oauth2基本使用
經過上面的步驟,相信和本菜一樣的小菜鳥多少熟悉了idea&maven的使用。接下來是使用spring-security-oauth2保護接口的安全。
1、導入依賴jar包
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
引入后啟動項目,觀察控制台,大概意思就是spring-security-oauth2給spring-mvc增加了一些Filter,因為都是出自於spring家族,我們不需要關心他們內部怎么實現,以及會不會有bug,我們關心的是如何去使用,更深點的是出了問題如何解決以及性能方面的考慮。本菜水平有限,此處只能列出使用。
那么繼續訪問http://localhost:8080/home,發現需要輸入用戶名、密碼,默認用戶名user,密碼會打印在控制台。
大功告成,spring-security-oauth2起作用了...
好吧,這只是開始,那么它是如何起的作用呢?
此處意思大概就是使用了“Basic”模式,后面是驗證信息,本菜大膽猜測是用戶名密碼。當然官方說這是不安全的,很容易被其他人模擬瀏覽器請求,例如curl和httpClient。
為了方便之后調試,將服務器端口號設置為9999,設置登錄密碼。resources目錄下新增application.yml文件,內容:
spring:
application:
name: oauth2_test
server:
port: 9999
management:
context_path: /
security:
user:
password: 123123
logging:
level:
# org.springframework.security: DEBUG
重啟server,登錄名和密碼變為user 123123
2、配置授權服務的類型
授權類型主要有
authorization_code:授權碼類型
implicit:隱式授權類型
password:資源所有者(即用戶)密碼類型
client_credentials:客戶端憑據(客戶端ID以及Key)類型
refresh_token:通過以上授權獲得的刷新令牌來獲取新的令牌
這里不考慮第2、4種授權類型。授權方法可以通過實現“AuthorizationServerConfigurer”接口或者繼承“AuthorizationServerConfigurerAdapter”類,重寫configure方法實現。
簡單介紹spring-security-oauth2的實現機制主要是通過token,客戶端發送請求時附上服務端給的token信息,如果驗證正確則通過,authorization_code在獲取token之前需要“第三方”認證,假設第三方提供給客戶端一個授權碼,客戶端即可以拿着“第三方”給的授權碼去服務器請求token。請求時需要一些參數,主要如下:
clientId:(必輸)用來標識客戶的Id
secret:(可選)客戶端安全碼,如果有的話
scope:用來限制客戶端的訪問范圍,如果為空(默認)的話,那么客戶端擁有全部的訪問范圍
authorizedGrantTypes:此客戶端可以使用的授權類型,默認為空
authorities:此客戶端可以使用的權限(基於Spring Security authorities)
對應的請求中默認參數名分別為client_id、secret、scope、grant_type、不需要。
配置示例代碼:
package com.pch.web;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
/**
* Created by Administrator on 2016/12/4.
*/
@RestController
public class UserController {
@RequestMapping("/user")
public Principal user(Principal user) {
return user;
}
}
package com.pch.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* Created by Administrator on 2016/12/4.
*/
@Configuration
@EnableResourceServer
public class CustomResouceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.tokenStore(tokenStore)
// .resourceId("resourceId")
;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/home")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/user")
.access("#oauth2.hasScope('read')")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
;
}
}
package com.pch.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* Created by Administrator on 2016/12/4.
*/
@Configuration
@EnableResourceServer
public class CustomResouceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.tokenStore(tokenStore)
// .resourceId("resourceId")
;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/home")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/user")
.access("#oauth2.hasScope('read')")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
;
}
}
這里不示例“authorization_code”方式認證
假設可以使用“CURL”命令,使用password方式認證命令:
curl -X POST client_id:@localhost:9999/oauth/token -d "grant_type=password" -d "client_id=client_id" -d "username=user" -d "password=123123"
將返回示例json:
{"access_token":"ea3595d6-e4c5-41d7-a6c8-f2e618f751a4","token_type":"bearer","refresh_token":"7792fdc7-53af-4bf5-8741-16ba9477db44","expires_in":2839,"scope":"read write"}
curl localhost:9999/home -H "Authorization: ${token_type} ${access_token}"