相關文章
1积暖、spring boot oauth2單點登錄(一)-前后端分離例子
2、spring boot oauth2單點登錄(二)-客戶端信息存儲
3爹橱、spring boot oauth2單點登錄(三)-token存儲方式
4、spring boot oauth2單點登錄(四)-code存儲方式
源碼地址
后端:https://gitee.com/fengchangxin/sso
前端:https://gitee.com/fengchangxin/sso-page
準備
后端:三個spring boot應用阁吝,auth(授權管理)崔赌,client1(客戶端應用1),client2(客戶端應用2)淆珊。
前端:三個Vue項目夺饲,auth,client1,client2往声。分別對應三個后端應用擂找。
工具:nginx
域名:oauth.com,client1.com浩销,client2.com贯涎,分別對應三個系統(tǒng)。
開發(fā)環(huán)境:先在host文件添加上面三個域名慢洋。
端口:
后端服務auth(8080)塘雳,client1(8081),client2(8082)普筹。
前端auth(8083)败明,client1(8084),client2(8085)太防。
依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
測試地址:
client1:http://client1.com/client1Page/#/home
client2:http://client2.com/client2Page/#/home
登錄用戶:admin/123456
備注:此篇文章對應的授權中心服務是:auth-db妻顶。
spring boot oauth2單點登錄(一)-實現(xiàn)例子通過這篇文章搭建了開發(fā)環(huán)境單點登錄,不過用戶信息和客戶端信息都是存儲在內存的蜒车,現(xiàn)在把這些信息存儲在數(shù)據(jù)庫盈包。
1、用戶信息
實現(xiàn)UserDetailsService接口的loadUserByUsername方法醇王,用戶登錄時通過此接口查詢數(shù)據(jù)庫返回賬戶密碼等信息呢燥。并在WebSecurityConfiguration添加配置。
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//TODO 在這里進行數(shù)據(jù)庫查詢獲取用戶信息
UserDetails user = User.withUsername("admin").password(passwordEncoder.encode("123456")).authorities("ADMIN", "USER").build();
return user;
}
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
2寓娩、客戶端信息
2.1默認實現(xiàn)
框架有默認的實現(xiàn)叛氨,我們只要在AuthorizationServerConfiguration配置好使用即可,數(shù)據(jù)庫表結構在resources下oauth.sql棘伴。需要注意的是在oauth_client_details表存儲的client_secret是經過PasswordEncoder加密處理的數(shù)據(jù)寞埠,不然無法登錄。
使用默認實現(xiàn)需要引入jdbc依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
@EnableAuthorizationServer
@Configuration
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients()
.checkTokenAccess("isAuthenticated()")
.tokenKeyAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(new JdbcClientDetailsServiceBuilder().dataSource(dataSource)
.passwordEncoder(passwordEncoder).build());
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
super.configure(endpoints);
}
}
2.2自定義實現(xiàn)
若表結構不符合要求焊夸,想要改變表結構仁连,不想用默認的實現(xiàn),那可以根據(jù)自己的需求來實現(xiàn)阱穗,主要是實現(xiàn)ClientDetailsService接口饭冬,并把結果組裝成BaseClientDetails返回。
舉個例子揪阶,自定義一張表client_details_test昌抠,結構和oauth_client_details一樣,多加了一個Id字段鲁僚,然后實現(xiàn)ClientDetailsService接口炊苫,需要注意的是這個實現(xiàn)類的bean名稱不能使用默認裁厅,需要重新命名。
@Service("clientDetailsManager")
public class ClientDetailsServiceImpl implements ClientDetailsService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
//TODO 自定義實現(xiàn)數(shù)據(jù)庫查詢
String sql = "select client_id,client_secret,resource_ids, scope, authorized_grant_types, web_server_redirect_uri, " +
"authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove from client_details_test where client_id=?";
return jdbcTemplate.queryForObject(sql,new ClientDetailsTestRowMapper(),clientId);
}
private static class ClientDetailsTestRowMapper implements RowMapper<ClientDetails> {
@Override
public ClientDetails mapRow(ResultSet rs, int i) throws SQLException {
BaseClientDetails details = new BaseClientDetails(rs.getString(1), rs.getString(3), rs.getString(4),
rs.getString(5), rs.getString(7), rs.getString(6));
details.setClientSecret(rs.getString(2));
if (rs.getObject(8) != null) {
details.setAccessTokenValiditySeconds(rs.getInt(8));
}
if (rs.getObject(9) != null) {
details.setRefreshTokenValiditySeconds(rs.getInt(9));
}
String scopes = rs.getString(11);
if (scopes != null) {
details.setAutoApproveScopes(StringUtils.commaDelimitedListToSet(scopes));
}
return details;
}
}
}
然后在AuthorizationServerConfiguration中配置侨艾。
@Autowired
private ClientDetailsService clientDetailsManager;
//自定義實現(xiàn)
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsManager);
}
總結:上面客戶端信息的兩種方式而選一执虹,根據(jù)實際情況選擇,默認實現(xiàn)表結構唠梨、表名是不可以變化的袋励,自定義實現(xiàn)可以結合mybatis等其他數(shù)據(jù)庫框架來靈活使用,表結構名稱等都可以自己設計姻成,比較靈活。而用戶登錄信息接口UserDetailsService也有默認實現(xiàn)愿棋,比如數(shù)據(jù)庫實現(xiàn)JdbcDaoImpl科展。
結合文章開頭列出的第一篇文章和此篇文章,就滿足了一般的單機應用糠雨,但對于集群部署的應用還是不夠才睹,token和授權碼code都是存在內存中,集群部署的會出問題甘邀,下列文章解決此問題琅攘。