因爲項目的關係,系統須要集成oAuth2.0功能。關於OAuth2.0的概念參考文章理解OAuth 2.0,或者 OAuth 2.0最簡嚮導html
咱們系統使用的Spring cloud G版本,引入依賴jar包redis
<!-- oAuth2 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
複製代碼
OAuth 2.0 定義了四種受權方式spring
在Spring OAuth2.0中除了定義以上四種受權模式外,還定義一個特殊的受權模式:刷新 四種模式和refresh模式對應的處理類是:數據庫
其餘一些重要的類:緩存
○ AuthorizationCodeServices:用於「受權碼模式( authorization code )」如何保存"受權碼",默認有兩種實現:bash
○ TokenStore:存儲token的方式,經常使用有如下幾種實現服務器
○ ClientDetailsService:客戶端帳號管理app
○ UserDetailsService:如何加載用戶帳號curl
○ 其餘ide
網上的案列基本是使用JdbcClientDetailsService 和 InMemoryClientDetailsService 實現客戶端帳號。這些都不符合咱們的要求。JdbcClientDetailsService 必須按照的標準創建相關的數據庫表,咱們的已經有本身的帳戶表,不能使用這些建立的表。
咱們首先研究InMemoryClientDetailsService裏返回的ClientDetails實例值以下:
@Service
public class MyClientDetailsService implements ClientDetailsService {
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
System.out.println("clientId = " + clientId);
// 實際使用時,這裏增長讀數據庫的操做,根據clientId獲取帳戶信息,並根據下面代碼的方式生成BaseClientDetails對象便可
BaseClientDetails baseClientDetails = new BaseClientDetails();
baseClientDetails.setClientId("clientapp");
// secret密碼配置從 Spring Security 5.0開始必須以 {加密方式}+加密後的密碼 這種格式填寫
/*
* 當前版本5新增支持加密方式:
* bcrypt - BCryptPasswordEncoder (Also used for encoding)
* ldap - LdapShaPasswordEncoder
* MD4 - Md4PasswordEncoder
* MD5 - new MessageDigestPasswordEncoder("MD5")
* noop - NoOpPasswordEncoder
* pbkdf2 - Pbkdf2PasswordEncoder
* scrypt - SCryptPasswordEncoder
* SHA-1 - new MessageDigestPasswordEncoder("SHA-1")
* SHA-256 - new MessageDigestPasswordEncoder("SHA-256")
* sha256 - StandardPasswordEncoder
*/
baseClientDetails.setClientSecret("{noop}112233");
// 不能夠設置爲null
// baseClientDetails.setAutoApproveScopes(null);
List<String> scopeList = new ArrayList<>();
scopeList.add("read_userinfo");
scopeList.add("read_contacts");
baseClientDetails.setScope(scopeList);
baseClientDetails.setResourceIds(null);
List<String> grantTypeList = new ArrayList<>();
grantTypeList.add("client_credentials");
// 運行刷新token
grantTypeList.add("refresh_token");
baseClientDetails.setAuthorizedGrantTypes(grantTypeList);
baseClientDetails.setRegisteredRedirectUri(Sets.newHashSet());
// 不能夠設置爲null
// baseClientDetails.setAuthorities(null);
// 設置accessToken和refreshToken有效期
baseClientDetails.setAccessTokenValiditySeconds(1000);
baseClientDetails.setRefreshTokenValiditySeconds(1000);
baseClientDetails.setAdditionalInformation(Maps.newHashMap());
return baseClientDetails;
}
}
複製代碼
在OAuth2AuthorizationServer中配置客戶端的帳戶的類
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Autowired
private MyClientDetailsService myClientDetailsService;
@Autowired
private RedisTokenStore redisTokenStore;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 配置客戶端的帳戶的類
clients.withClientDetails(myClientDetailsService);
}
複製代碼
測試
curl -X POST "http://10.216.33.211:10808/com-oauth/oauth/token" --user clientapp:112233 -d "grant_type=client_credentials&scope=read_contacts 返回: {"access_token":"9ba822ce-3c1b-461f-85bb-722e83c30248","token_type":"bearer","expires_in":28068,"scope":"read_contacts"} 複製代碼
默認使用,使用內存用戶帳號
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user_1").password("123456").authorities("USER")
.and()
.withUser("user_2").password("123456").authorities("USER");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
AuthenticationManager manager = super.authenticationManagerBean();
return manager;
}
}
複製代碼
使用自定義用戶帳號 咱們要實現本身的系統,實現UserDetailsService 接口,根據用戶名稱,若是驗證成功,則返回UserDetails 對象。實際應用將這裏增長訪問本身用戶帳號的功能便可。
@Service
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
System.out.println("name=" + s);
// 獲取用戶權限列表
List<GrantedAuthority> authorities = new ArrayList();
authorities.add(new SimpleGrantedAuthority("admin"));
authorities.add(new SimpleGrantedAuthority("default"));
if(s.equals("hry")) {
String name = "hry";
String password = "1024";
User user = new User(name, password, true, true, true, true, authorities);
return user;
}else {
String name = "default";
String password = "1024";
User user = new User(name, password, true, true, true, true, authorities);
return user;
}
}
}
複製代碼
@EnableWebSecurity 註解類,並實現WebSecurityConfigurerAdapter 的configure(AuthenticationManagerBuilder auth)設置UserDetailsService 的對象
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Autowired
private MyUserDetailsService myUserDetailsService;
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.userDetailsService(myUserDetailsService);
}
}
複製代碼
token的存儲由TokenStore實現。TokenStore:存儲token的方式,經常使用有如下幾種實現
咱們使用RedisTokenStore實現redis存儲 @EnableAuthorizationServer:標記這是權限服務器
@Configuration
// enables the Authorization server configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {
@Autowired
private RedisTokenStore redisTokenStore;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
super.configure(endpoints);
// 默認狀況配置在緩存中,若是配置這個,則存儲在redis中
endpoints.tokenStore(redisTokenStore);
}
}
複製代碼
初始化RedisTokenStore
@Bean
public RedisTokenStore createRedisTokenStore(RedisConnectionFactory connectionFactory){
return new RedisTokenStore(connectionFactory);
}
複製代碼