OAuth2 是什么 OAuth2 其实是一个关于授权的网络标准,它制定了设计思路和运行流程,利用这个标准我们其实是可以自己实现 OAuth2 的认证过程的。 spring-cloud-starter-oauth2 是 Spring Cloud 按照 OAuth2 的标准并结合 spring-security 封装好的一个具体实现。
OAuth 2 有四种授权模式,分别是授权码模式(authorization code)、简化模式(implicit)、密码模式(resource owner password credentials)、客户端模式(client credentials),具体 OAuth2 是什么,可以参考这篇文章(http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
)。
OAuth2 的使用场景 典型的 OAuth2 使用场景:微信登录、QQ 登录、微博登录、Google 帐号登录、Github 帐号登录等。第一次使用就无需注册,直接通过第三方平台授权登录即可,大大提高了使用效率。此外,服务不需要存储用户的密码,只需要存储认证平台返回的唯一 ID 和用户信息即可。 不使用 OAuth2 的场景:用户需要先完成注册,然后用注册号的帐号密码或者用手机验证码登录。
OAuth2 实现统一认证功能
创建并配置认证服务端 auth-server 认证服务端负责验证帐号、密码、存储 Token、检查 Token、刷新 Token 等。
1、引入需要的 Maven 包 1
2
3
4
5
6
7
8
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId> spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId> spring-boot-starter-oauth2</artifactId>
</dependency>
2、配置 bootstrap.yml 和 Nacos 配置 认证服务器采用 Nacos Config 方案,将配置放在 Nacos 注册中心上
1
2
3
4
5
6
7
8
9
10
spring :
application :
name : auth-server
cloud :
nacos :
config :
prefix : auth-server-config
server-addr : xxxx
file-extension : yaml
group : refactored-spring-cloud
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
server :
port : 18003
spring :
datasource :
url : jdbc:mysql://xxxx:3306/spring?useUnicode=true&&characterEncoding=UTF-8&&serverTimezone=Asia/Shanghai
username : xxxx
password : xxxx
jpa :
show-sql : true
generate-ddl : true
database-platform : org.hibernate.dialect.MYSQL5InnoDBDialect
database : mysql
application :
name : auth-server
cloud :
nacos :
discovery :
server-addr : xxxx:8848
group : refactored-spring-cloud
inetutils :
ignored-interfaces : eth.*
preferred-networks : xxxx
redis :
host : xxxx
port : 6379
management :
endpoint :
health :
enabled : true
dubbo :
protocol :
name : dubbo
port : -1
registry :
address : spring-cloud://xxxx
consumer :
timeout : 3000
3、配置 Spring Security 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder () {
return new BCryptPasswordEncoder ();
}
@Bean
@Override
public AuthenticationManager authenticationManager () throws Exception {
return super . authenticationManager ();
}
/**
* 开放所有接口
*/
@Override
protected void configure ( HttpSecurity http ) throws Exception {
http . authorizeRequests ()
. antMatchers ( "/**" )
. permitAll ();
}
}
PasswordEncoder:采用 BCrypt 加密算法 AuthenticationManager:OAuth2 密码模式必须制定的授权管理,用默认的即可 configure:配置拦截器,使用通配符开放所有接口访问权限
4、实现 UserDetailsService 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Slf4j
@Commponent ( value = "kiteUserDetailService" )
public class KiteUserDetailService implements UserDetailService {
@DubboReference
IUserService service ;
@Override
public UserDetails loadUserByUsername ( String username ) throws UsernameNotFoundException {
log . info ( "username is: " + username );
// 查询用户
if ( user == null ) {
throw new UsernameNotFoundException ( "The user is not found" );
} else {
// 查询角色
List < SysRole > roles = user . getRoles ();
List < SimpleGrantedAuthority > authorities = new ArrayList <> ();
for ( SysRole role : roles ) {
authorities . add ( new SimpleGrantedAuthority ( role . getRoleName ()));
}
// 查询密码
String password = user . getPassword ();
return new User ( username , password , authorities );
}
}
}
loadUserByUsername:首先利用用户微服务接口通过 username 查询用户、角色以及密码,然后返回org.springframework.security.core.userdetails.User
即可。
5、配置 OAuth2 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
public PasswordEncoder passwordEncoder ;
@Autowired
public UserDetailsService kiteUserDetailsService ;
@Autowired
private TokenStore jwtTokenStore ;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter ;
@Autowired
private DataSource dataSource ;
@Override
public void configure ( final AuthorizationServerEndpointsConfigurer endpoints ) throws Exception {
// Redis token 方式
endpoints . authenticaionManager ( authenticationManager )
. userDetailsService ( kiteUserDetailsService )
. accessTokenConverter ( jwtAccessTokenConverter )
. tokenStore ( jwtTokenStore );
}
@Override
public void configure ( ClientDetailsServiceConfigurer clients ) throws Exception {
JdbcClientDetailsServiceBuilder builder = clients . jdbc ( dataSource );
builder . passwordEncoder ( passwordEncoder );
}
@Override
public void configure ( AuthorizationServerSecurityConfigurer security ) throws Exception {
security . allowFromAuthenticationForClients ();
security . checkTokenAccess ( "isAuthenticated" );
security . tokenKeyAccess ( "isAuthenticated" );
}
}
有三个 configure 方法的重写
1
2
3
4
5
6
7
8
9
10
11
12
13
create table oauth_client_details (
client_id VARCHAR ( 256 ) PRIMARY KEY ,
resource_ids VARCHAR ( 256 ),
client_secret VARCHAR ( 256 ),
scope VARCHAR ( 256 ),
authorized_grant_types VARCHAR ( 256 ),
web_server_redirect_uri VARCHAR ( 256 ),
authorities VARCHAR ( 256 ),
access_token_validity INTEGER ,
refresh_token_validity INTEGER ,
additional_information VARCHAR ( 4096 ),
autoapprove VARCHAR ( 256 )
);
6、配置 JWTTokenStore 1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
public class JWTTokenStore {
@Bean
public TokenStore jwtTokenStore () {
return new JwtTokenStore ( jwtAccessTokenConverter ());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter () {
JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter ();
accessTokenConverter . setSigningKey ( "dev" );
return accessTokenConverter ;
}
}
7、启动 auth-server 现在已经可以访问 OAuth2 相关的 Restful 接口:
POST /oauth/authorize 授权码模式认证授权接口 GET/POST /oauth/token 获取 token 的接口 POST /oauth/check_token 检查 token 合法性接口