1.项目地址
2.基本概念
主要角色
- 第三方应用程序(
Third-party application
): 又称之为客户端(client
) - 服务提供商(
HTTP service
): 我们的云笔记产品以及 QQ、微信等都可以称之为“服务提供商”。 - 资源所有者(
Resource Owner
): 又称之为用户(user
)。 - 用户代理(
User Agent
): 比如浏览器,代替用户去访问这些资源。 - 认证服务器(
Authorization server
):
即服务提供商专门用来处理认证的服务器,简单点说就是登录功能(验证用户的账号密码是否正确以及分配相应的权限) - 资源服务器(
Resource server
):
即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。简单点说就是资源的访问入口,比如“云笔记服务”和“云相册服务”都可以称之为资源服务器。
grant_type
:端点类型
authorization_code
: 授权码模式,根据client
账号密码获取授权码code
,在根据授权码获取tokenpassword
: 密码模式,使用用户账号密码登录获取tokenrefresh_token
: 开放端点进行刷新access_token
client_credentials
: 客户端模式implicit
: 简化模式token_key
: 用于单点登录的端点token_error
:错误回调端点
client_detail
:客户端详情
-
client_id
: 客户端唯一ID
,相当于账号 -
client_secret
: 客户端秘钥,相当于密码 -
resource_ids
: 客户端拥有资源 -
scope
: 客户端权限范围标识 -
authorized_grant_types
: 同上grant_type
-
web_server_redirect_uri
: 授权成功后的回调地址 -
authorities
: 客户端拥有的权限资源 -
access_token_validity
:token
的过期时间 -
refresh_token_validity
:refresh_token
的失效时间 -
additional_information
: 附加信息 -
autoapprove
: 开启自动授权,true
or
false
-
主要流程图
2.认证服务器搭建
Pom.xml
<!-- Spring Cloud 和 oauth2支持的同时需要引用web开始filter的支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 配置授权服务
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Autowired
@Qualifier("jwtTokenStore") //需要指定名称,不然注册其他的。
private TokenStore tokenStore;
@Autowired
private JwtAccessTokenConverter jwtAccessTokenConverter;
/**
* 刷新令牌需要使用自定义的授权服务
*/
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
/**
* JDBC令牌存储
* 访问形式: xxx/xxx?access_token=xxxx
* @return
*/
// @Bean
// public TokenStore tokenStore() {
// // 基于 JDBC 实现,令牌保存到数据
// return new JdbcTokenStore(dataSource);
// }
@Bean
public ClientDetailsService jdbcClientDetails() {
// 基于 JDBC 实现,需要事先在数据库配置客户端信息
return new JdbcClientDetailsService(dataSource);
}
/**
* 配置token的存储和时间等属性
* @return
*/
// @Bean
// public DefaultTokenServices tokenServices(){
// DefaultTokenServices tokenServices = new DefaultTokenServices();
// tokenServices.setAccessTokenValiditySeconds(20);//设置20秒过期
// tokenServices.setRefreshTokenValiditySeconds(666);//设置刷新token的过期时间
// tokenServices.setTokenStore(tokenStore);
// return tokenServices;
// }
/**
* http://localhost:8080/oauth/token
* 参数:
* grant_type : authorization_code,password
* code: 授权密码
* 或者:
* username:xx
* password:xx
*
* 并且要加上Authorization的用户名密码就是
* client_id 和 client_secret
* @param endpoints 授权服务器端点令牌配置
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 设置令牌
endpoints
.authenticationManager(authenticationManager)
//刷新token需要配置userDetailsService重新加载权限,需要在authenticationManager之后配置
.userDetailsService(userDetailsService)
.tokenStore(tokenStore)
.accessTokenConverter(jwtAccessTokenConverter);
// .tokenServices(tokenServices());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
// exposes public key for token verification if using JWT tokens
// 允许Jwt token验证秘钥
.tokenKeyAccess("permitAll()")
// used by Resource Servers to decode access tokens
// 允许已认证的资源服务器解码token,单点登录需要
.checkTokenAccess("isAuthenticated()")
/**
* allowFormAuthenticationForClients是为了注册clientCredentialsTokenEndpointFilter
* clientCredentialsTokenEndpointFilter,解析request中的client_id和client_secret
* 构造成UsernamePasswordAuthenticationToken,然后通过UserDetailsService查询作简单的认证而已
* 一般是针对password模式和client_credentials
* 当然也可以使用http basic认证
* 如果使用了http basic认证,就不用使用clientCredentialsTokenEndpointFilter,因为本质是一样的
*/
.allowFormAuthenticationForClients();
}
/**
* 客户端配置
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 读取客户端配置
clients.withClientDetails(jdbcClientDetails());
}
}