@TOCjava
OAuth2.0系列博客:git
在前面文章中咱們學習了OAuth2的一些基本概念,對OAuth2有了基本的認識,也對OAuth2.0的令牌等進行數據庫存儲,對應博客:jdbc方式的數據存儲,而後若是不想存儲令牌能夠實現?github
IDEA中,Ctrl+Alt+B,能夠看到TokenStore的實現,有以下幾種: web
實驗環境準備:redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud Oauth2-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<!-- Spring Cloud Security-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
複製代碼
TokenStore:spring
@Bean
public TokenStore jwtTokenStore() {
//基於jwt實現令牌(Access Token)
return new JwtTokenStore(accessTokenConverter());
}
複製代碼
JwtAccessTokenConverter :數據庫
@Bean
public JwtAccessTokenConverter accessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter(){
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String grantType = authentication.getOAuth2Request().getGrantType();
//受權碼和密碼模式才自定義token信息
if(AUTHORIZATION_CODE.equals(grantType) || GRANT_TYPE_PASSWORD.equals(grantType)) {
String userName = authentication.getUserAuthentication().getName();
// 自定義一些token 信息
Map<String, Object> additionalInformation = new HashMap<String, Object>(16);
additionalInformation.put("user_name", userName);
additionalInformation = Collections.unmodifiableMap(additionalInformation);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
}
OAuth2AccessToken token = super.enhance(accessToken, authentication);
return token;
}
};
// 設置簽署key
converter.setSigningKey("signingKey");
return converter;
}
複製代碼
配置accessTokenConverterjson
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(jwtTokenStore()).authenticationManager(authenticationManager)
//自定義accessTokenConverter
.accessTokenConverter(accessTokenConverter())
//支持獲取token方式
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST,HttpMethod.PUT,HttpMethod.DELETE,HttpMethod.OPTIONS);
}
複製代碼
總的配置類參考:跨域
package com.example.springboot.oauth2.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
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;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/** * <pre> * OAuth2.0配置類 * </pre> * * <pre> * @author mazq * 修改記錄 * 修改後版本: 修改人: 修改日期: 2020/06/17 11:44 修改內容: * </pre> */
@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
private static final String CLIENT_ID = "cms";
private static final String SECRET_CHAR_SEQUENCE = "{noop}secret";
private static final String SCOPE_READ = "read";
private static final String SCOPE_WRITE = "write";
private static final String TRUST = "trust";
private static final String USER ="user";
private static final String ALL = "all";
private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60;
private static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 2*60;
// 密碼模式受權模式
private static final String GRANT_TYPE_PASSWORD = "password";
//受權碼模式
private static final String AUTHORIZATION_CODE = "authorization_code";
//refresh token模式
private static final String REFRESH_TOKEN = "refresh_token";
//簡化受權模式
private static final String IMPLICIT = "implicit";
//指定哪些資源是須要受權驗證的
private static final String RESOURCE_ID = "resource_id";
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
// 使用內存存儲
.inMemory()
//標記客戶端id
.withClient(CLIENT_ID)
//客戶端安全碼
.secret(SECRET_CHAR_SEQUENCE)
//爲true 直接自動受權成功返回code
.autoApprove(true)
.redirectUris("http://127.0.0.1:8084/cms/login") //重定向uri
//容許受權範圍
.scopes(ALL)
//token 時間秒
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
//刷新token 時間 秒
.refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS)
//容許受權類型
.authorizedGrantTypes(GRANT_TYPE_PASSWORD , AUTHORIZATION_CODE , REFRESH_TOKEN , IMPLICIT);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(jwtTokenStore()).authenticationManager(authenticationManager)
//自定義accessTokenConverter
.accessTokenConverter(accessTokenConverter())
//支持獲取token方式
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST,HttpMethod.PUT,HttpMethod.DELETE,HttpMethod.OPTIONS);
}
/** * 認證服務器的安全配置 * @param security * @throws Exception */
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
// 開啓/oauth/token_key驗證端口認證權限訪問
.tokenKeyAccess("isAuthenticated()")
// 開啓/oauth/check_token驗證端口認證權限訪問
.checkTokenAccess("isAuthenticated()")
//容許表單認證
.allowFormAuthenticationForClients();
}
@Bean
public JwtAccessTokenConverter accessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter(){
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String grantType = authentication.getOAuth2Request().getGrantType();
//受權碼和密碼模式才自定義token信息
if(AUTHORIZATION_CODE.equals(grantType) || GRANT_TYPE_PASSWORD.equals(grantType)) {
String userName = authentication.getUserAuthentication().getName();
// 自定義一些token 信息
Map<String, Object> additionalInformation = new HashMap<String, Object>(16);
additionalInformation.put("user_name", userName);
additionalInformation = Collections.unmodifiableMap(additionalInformation);
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);
}
OAuth2AccessToken token = super.enhance(accessToken, authentication);
return token;
}
};
// 設置簽署key
converter.setSigningKey("signingKey");
return converter;
}
@Bean
public TokenStore jwtTokenStore() {
//基於jwt實現令牌(Access Token)
return new JwtTokenStore(accessTokenConverter());
}
}
複製代碼
SpringSecurity配置類:瀏覽器
package com.example.springboot.oauth2.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
/** * <pre> * Spring Security配置類 * </pre> * * <pre> * @author mazq * 修改記錄 * 修改後版本: 修改人: 修改日期: 2020/06/15 10:39 修改內容: * </pre> */
@Configuration
@EnableWebSecurity
@Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { //auth.inMemoryAuthentication()
auth.inMemoryAuthentication()
.withUser("nicky")
.password("{noop}123")
.roles("admin");
}
@Override
public void configure(WebSecurity web) throws Exception {
//解決靜態資源被攔截的問題
web.ignoring().antMatchers("/asserts/**");
web.ignoring().antMatchers("/favicon.ico");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http // 配置登陸頁並容許訪問
.formLogin().permitAll()
// 配置Basic登陸
//.and().httpBasic()
// 配置登出頁面
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/")
.and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll()
// 其他全部請求所有須要鑑權認證
.anyRequest().authenticated()
// 關閉跨域保護;
.and().csrf().disable();
}
}
複製代碼
訪問受權連接,在瀏覽器訪問就能夠,受權碼模式response_type參數傳code: http://localhost:8888/oauth/authorize?client_id=cms&client_secret=secret&response_type=code
由於沒登陸,因此會返回SpringSecurity的默認登陸頁面,具體代碼是http .formLogin().permitAll();
,若是要彈窗登陸的,能夠配置http.httpBasic();
,這種配置是沒有登陸頁面的,自定義登陸頁面能夠這樣配置http.formLogin().loginPage("/login").permitAll()
如圖,輸入SpringSecurity配置的數據庫密碼
登陸成功,返回redirect_uri,拿到受權碼
重定向回redirect_uri,http://localhost:8084/cms/login?code=???
配置一下請求頭的受權參數,用Basic Auth方式,username即client_id,password即client_secret
{
"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1OTIzNzYwNjEsInVzZXJfbmFtZSI6Im5pY2t5IiwiYXV0aG9yaXRpZXMiOlsiUk9MRV9hZG1pbiJdLCJqdGkiOiJiM2IwZGExNS1mMmQyLTRlN2MtYTUwNC1iMzg5YjkxMjM0MDMiLCJjbGllbnRfaWQiOiJjbXMiLCJzY29wZSI6WyJhbGwiXX0.TpIBd9Gtb4M7sC1MSQsxsn8mwnhAm59CUBZPU7jwdnE",
"token_type":"bearer",
"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJuaWNreSIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiJiM2IwZGExNS1mMmQyLTRlN2MtYTUwNC1iMzg5YjkxMjM0MDMiLCJleHAiOjE1OTIzNzYwNjEsImF1dGhvcml0aWVzIjpbIlJPTEVfYWRtaW4iXSwianRpIjoiODVhYTlmMGYtNDliNS00NDg4LTk4MTQtNmM0MmZjMjZkYTc2IiwiY2xpZW50X2lkIjoiY21zIn0.TU8ZD_5AxRGbgbOWZSuWAxwWjMJ4HLHniA46M-dnChE",
"expires_in":119,
"scope":"all",
"user_name":"nicky",
"jti":"b3b0da15-f2d2-4e7c-a504-b389b9123403"
}
複製代碼
例子代碼下載:code download