Spring boot+Security OAuth2 爬坑日記(1)授權碼模式
阿新 • • 發佈:2018-11-11
OAuth2
OAuth 關於授權的開放網路標準,關於OAuth2的知識,參考OAuth2.0 和 理解OAuth 2.0-阮一峰
四種授權模式
- 授權碼模式 (功能最完整,流程最嚴密)
- 密碼模式
- 客戶端模式
- 簡化模式
授權碼模式
開發環境
系統:Mac / Win10 兩個開發環境交替使用
JDK:java11(Mac),java8(Win10)
IDEA:Intellij IDEA (2018.1-win),Intellij IDEA (2018.3-mac)
專案管理: maven 3.5
maven 依賴
< parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</ groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId >org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.11</version>
</dependency>
</dependencies>
認證服務配置
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
// 允許表單登入
security.allowFormAuthenticationForClients();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
String secret = passwordEncoder.encode("123qwe");
clients
// 客戶端資訊儲存在記憶體中
.inMemory()
// 客戶端 id
.withClient("client")
// 跳轉uri
.redirectUris("http://localhost")
// 客戶端 secret
.secret(secret)
// 授權模式
.authorizedGrantTypes("refresh_token","authorization_code");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
// tonken 儲存於記憶體中
.tokenStore(new InMemoryTokenStore())
.authenticationManager(authenticationManager);
}
}
資源服務配置
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter{
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
super.configure(resources);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.formLogin().and()
.requestMatchers().anyRequest()
.and()
.authorizeRequests()
.antMatchers("/oauth/**","/login").permitAll()
.anyRequest().authenticated();
}
}
WebSecurity 配置
@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private BootUserDetailService userDetailService;
@Autowired
private BootLoginSuccessHandler bootLoginSuccessHandler;
/**
* 讓Security 忽略這些url,不做攔截處理
* @param web
* @throws Exception
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers
("/swagger-ui.html/**", "/webjars/**",
"/swagger-resources/**", "/v2/api-docs/**",
"/swagger-resources/configuration/ui/**", "/swagger-resources/configuration/security/**",
"/images/**");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailService);
}
@Override
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
自定義 UserDetailsService
@Component
public class BootUserDetailService implements UserDetailsService {
@Autowired
private IUserService userService;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user= this.userService.findByUserName(username);
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List <GrantedAuthority>authorities = new ArrayList<>();
authorities.add(authority);
user.setAuthorities(authorities);
if(user==null) {
throw new UsernameNotFoundException("使用者名稱不存在");
}
return user;
}
}
啟動系統後在控制檯中打印出如下的請求介面
/oauth/authorize 使用者確認授權路徑
/oauth/token 獲取token的路徑
參考OAuth2.0 官網的文件,請求授權的路徑為
GET http://localhost:8000/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://localhost&scope=select
訪問該URL 登入後會出現如下的請求授權的頁面
點選(Authorize)確認授權,之後會跳轉到預先在請求授權URL中設定的(redirect_uri)的引數值指定的頁面並帶上授權碼,跳轉後出現如下頁面
得到授權碼之後,請求獲取Token ,請求引數如下
到這裡就獲取到了Token,接下來就可以帶上Token去請求相關的資源
如果不帶上Token,將會有如下錯誤
到這裡簡單的OAuth2的授權碼模式完成,接下來總結下在完成這個接單示例的過程中遇到的坑:
- 在授權之前必須完成登入,所以
WebSecurityConfig
必須必須在ResourceServerConfig
之前,如果不是的話就會出現如下異常
User must be authenticated with Spring Security before authorization can be completed.
原始碼地址 Github ,
微信公眾號: