Spring boot+Security OAuth2 爬坑日記(2)授權碼模式(升級篇)
阿新 • • 發佈:2018-11-11
1. 開發環境和本專案用到的框架
接著上一篇Spring boot+Security OAuth2 爬坑日記(1)授權碼模式部落格中的內容,上篇介紹了基本的開發環境,系統以及jdk版本等,本篇再來詳細介紹下專案中用到的框架和相關類庫。
框架/類庫/資料庫 | 版本號 |
---|---|
java | 11(Mac)/ 8(Win10) |
spring-boot | 2.0.5.RELEASE |
spring-security | 5.0.8.RELEASE |
spring-security-oauth2 | 2.3.3.RELEASE |
mybatis-plus | 3.0.4 |
資料庫連線池(druid) | 1.1.11 |
swagger-ui | 2.9.2 |
hibernate-validator | 6.0.13.Final |
MySQL | 5.7.22 MySQL Community Server |
Redis | 4.0.10 |
通過上述版本發現spring系列的版本都是最新的釋出版本,網上示例基本不多,使用必然會出現很多坑;當然有坑之後爬坑才能進步。可能有的人奇怪我為什麼用兩個版本,公司用肯定用java8,在自己的機器裡肯定用最新版來試水咯。。不說了老闆讓我修復趕緊修復bug,不然今天不能下班。。。。。。。。。。
上篇部落格中我們的客戶端資訊都是儲存在記憶體中的,本篇將客戶端資訊儲存於資料庫中;廢話不多說,開始擼碼!!!!!!!!
2. 專案結構
3. 自定義BootClientDetailsService
和BootClientDetails
並配置
新建類 BootClientDetailsService
ClientDetailsService
介面,覆蓋loadClientByClientId(String clientId)
方法,將其宣告為spring元件,方便後面配置使用
@Component
public final class BootClientDetailsService implements ClientDetailsService {
@Autowired
private IClientService clientService;
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
Client client = this.clientService.findClientByClientId(clientId);
if(client==null){
throw new ClientRegistrationException("客戶端不存在");
}
return new BootClientDetails(client);
}
}
@Data
public final class BootClientDetails implements ClientDetails {
private Client client;
public BootClientDetails(Client client) {
this.client = client;
}
public BootClientDetails() {
}
@Override
public String getClientId() {
return client.getClientId();
}
@Override
public Set<String> getResourceIds() {
return client.getResourceIds()!=null?
transformStringToSet(client.getResourceIds(),String.class):null;
}
@Override
public boolean isSecretRequired() {
return client.getIsSecretRequired();
}
@Override
public String getClientSecret() {
return client.getClientSecret();
}
@Override
public boolean isScoped() {
return client.getIsScoped();
}
@Override
public Set<String> getScope() {
return client.getScope()!=null?
transformStringToSet(client.getScope(),String.class):null;
}
@Override
public Set<String> getAuthorizedGrantTypes() {
return client.getAuthorizedGrantTypes()!=null?
transformStringToSet(client.getAuthorizedGrantTypes(),String.class):null;
}
@Override
public Set<String> getRegisteredRedirectUri() {
return client.getRegisteredRedirectUri()!=null?
transformStringToSet(client.getRegisteredRedirectUri(),String.class):null;
}
@Override
public Collection<GrantedAuthority> getAuthorities() {
return (client.getAuthorities()!=null&&client.getAuthorities().trim().length()>0)?
AuthorityUtils.commaSeparatedStringToAuthorityList(client.getAuthorities()):null;
}
@Override
public Integer getAccessTokenValiditySeconds() {
return client.getAccessTokenValiditySeconds();
}
@Override
public Integer getRefreshTokenValiditySeconds() {
return client.getRefreshTokenValiditySeconds();
}
@Override
public boolean isAutoApprove(String scope) {
return client.getIsAutoApprove();
}
@Override
public Map<String, Object> getAdditionalInformation() {
return null;
}
}
將我們定義的 BootClientDetailsService
配置在OAuth2AuthorizationServerConfig
中
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private BootClientDetailsService clientDetailsService;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// 允許表單登入
security.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// String secret = passwordEncoder.encode("123qwe");
clients.withClientDetails(clientDetailsService);
/*// 客戶端儲存資訊儲存於記憶體中
.inMemory()
// 客戶端名稱
.withClient("client")
// 跳轉uri,可配置多個
.redirectUris("http://localhost")
// 許可權
// .authorities("ROLE_USER")
// 客戶端 secret
.secret(secret)
// 授權模式
.authorizedGrantTypes("refresh_token","authorization_code");*/
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(new InMemoryTokenStore())
.authenticationManager(authenticationManager);
}
}
4. 建立註冊客戶端的介面ClientController
@RestController
@RequestMapping("client")
public class ClientController {
@Autowired
private IClientService clientService;
@Autowired
private PasswordEncoder passwordEncoder;
@PostMapping("/register")
public BaseResponse clientRegistered(@RequestBody @Valid Client client){
client.setClientSecret(passwordEncoder.encode(client.getClientSecret()));
int i= clientService.insert(client);
return HttpResponse.baseResponse(200);
}
}
完成客戶端註冊介面後,將客戶端註冊介面開放,不需要認證就能訪問
@Override
public void configure(HttpSecurity http) throws Exception {
http.formLogin().and()
.authorizeRequests()
.antMatchers("/login","/oauth/*","/client/register")
.permitAll()
.antMatchers
("/swagger-ui.html/**","/webjars/**",
"/swagger-resources/**","/v2/api-docs/**",
"/swagger-resources/configuration/ui/**","/swagger-resources/configuration/security/**",
"/images/**")
.permitAll()
.anyRequest()
.authenticated()
.and().csrf().disable();
}
5. 測試
專案中已經整合好了swagger-ui,專案啟動後直接訪問http://localhost:8000/swagger-ui.html,出現如下頁面
通過swagger-ui註冊客戶端,請求引數如下
{
"accessTokenValiditySeconds": 1800,
"authorities": "ADMIN",
"authorizedGrantTypes": "refresh_token,authorization_code",
"clientId": "client1",
"clientSecret": "123qwe",
"isAutoApprove": false,
"isSecretRequired": true,
"refreshTokenValiditySeconds": 3600,
"registeredRedirectUri": "http://localhost:7000",
"scope": "all",
"scoped": true,
"secretRequired": true
}
客戶端註冊成功後就可以使用該客戶端的資訊申請授權,申請授權的步驟和Spring boot+Security OAuth2 爬坑日記(1)授權碼模式中的一樣,這裡不再贅述
原始碼地址 Github
微信公眾號: