一.简介
OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。OAuth2.0是OAuth协议的延续版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0。
在APP或者网页接入一些第三方应用时,时长会需要用户登录另一个合作平台,比如QQ,微博,微信的授权登录。
OAuth 提供三种角色,分别是:
- 服务提供方(Authorization Server)
- 资源持有者(Resource Server)
- 客户端(Client)
认证流程如下:
- 1.用户(资源持有者)打开客户端,客户端询问用户授权。
- 2.用户同意授权。
- 3.客户端向授权服务器申请授权。
- 4.授权服务器对客户端进行认证,包括用户信息认证,认证成功后授予令牌。
- 5.客户端获取令牌后,携带令牌向资源服务器请求资源。
- 6.资源服务器确定令牌正确无误,向客户端释放资。
二.Spring Cloud OAuth2 的使用
本实例包含三个服务,服务注册中心(server-service),客户端(client-service),以及授权服务(oauth-service),客户端和授权服务向注册中心注册,授权服务负责授权给客户端,之后客户端能访问相关的资源。
Spring OAuth2 分为两部分,分别是:
- OAuth2 Provider
- OAuth2 Client
OAuth2 Provider 负责公开被OAuth保护起来的资源,需要配置代表用户的OAuth 客户端信息,被允许的用户就可以访问被oauth保护的资源,OAuth2 Provider需要提供认证的API接口,用户通过账号密码来获取权限去访问被OAuth保护的资源,OAuth2 Provider 又可分为两部分:
- Authorization Server(授权服务)
- Resources Server(资源服务)
他们通常不在一个服务中,一个授权服务可以对应多个资源服务,资源服务也可以是授权服务。
OAuth2 Provider
Authorization Server(授权服务) 配置
//授权服务
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
//@Autowired
//@Qualifier("dataSource")
private DataSource dataSource;
//配置将Token存储到内存
private TokenStore tokenStore = new InMemoryTokenStore();
//配置将Token存储到数据库
//JdbcTokenStore tokenStore=new JdbcTokenStore(dataSource);
//配置开启密码类型的验证,只有配置了才会开启
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private UserService userServiceDetail;
//配置客户端的基本信息
@Override
//配置客户端信息
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
String finalSecret = new BCryptPasswordEncoder().encode("123456");
clients.inMemory()
//客户端Id,在Authorization Server 是唯一的
.withClient("client-service")
//认证类型
//客户端模式
.authorizedGrantTypes("client_credentials", "password","refresh_token")
//权限范围
.scopes("server")
//权限信息
.authorities("oauth2")
//客户端密码
.secret(finalSecret)
//密码模式
.and().withClient("client_2")
.authorizedGrantTypes("password", "refresh_token")
.scopes("server")
.authorities("oauth2")
.secret(finalSecret)
.accessTokenValiditySeconds(2*3600);//2小时过期
}
@Override
//配置Token节点的安全策略
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore)//Token的存储方式
//.tokenStore(new RedisTokenStore(redisConnectionFactory))
.authenticationManager(authenticationManager)//开启密码类型的验证
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
//配置读取用户验证信息,获取用户认证信息的接口
.userDetailsService(userServiceDetail);
//endpoints.reuseRefreshTokens(true);
}
@Override
//配置授权Token的节点和Token服务
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
//配置获取Token的策略,允许表单认证,配置之后可通过表单获取Token
oauthServer.allowFormAuthenticationForClients();
}
}
Spring Security 认证配置
@Configuration
@EnableWebSecurity//开启WebSecurity功能
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启方法上的保护
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.anyRequest()
.and().authorizeRequests()
//.antMatchers("/admin/**").authenticated()
.antMatchers("/css/**", "/test","/oauth/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")///admin/**的URL都需要有超级管理员角色,如果使用.hasAuthority()方法来配置,需要在参数中加上ROLE_,如下.hasAuthority("ROLE_超级管理员")
.anyRequest().authenticated();//其他的路径都是登录后即可访问
}
//配置验证管理的Bean
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Resources Server(资源服务) 配置
//配置资源服务
//@Configuration
//@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
//资源访问控制,可配置必须通过token认证过后才可以访问的资源,permitAll()表示不需要token可直接访问
http
.authorizeRequests()
.antMatchers("/login").permitAll();
}
}
OAuth2 Client
客户端用来访问被 OAuth保护起来的资源,需要配置
- Protected Resource Configuration(受保护的资源配置)
security:
oauth2:
resource:
user-info-uri: http://localhost:8763/current
client:
# 客户端Id ,与OAuth Provider 中的配置一一对应
clientId: client-service
# 客户端密码,与OAuth Provider 中的配置一一对应
clientSecret: 123456
# 获取Token的节点
accessTokenUri: http://localhost:8763/oauth/token
grant-type: client_credentials,password
# 客户端的域
scope: server
- Client Configuration(客户端配置)
@EnableOAuth2Client
@EnableConfigurationProperties
@Configuration
public class OAuth2ClientConfig {
//配置受保护的资源信息
@Bean
@ConfigurationProperties(prefix = "security.oauth2.client")
public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
return new ClientCredentialsResourceDetails();
}
//配置过滤器,存储当前请求和上下文
/*@Bean
public RequestInterceptor oauth2FeignRequestInterceptor(){
return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails());
}*/
@Bean
public OAuth2RestTemplate clientCredentialsRestTemplate() {
return new OAuth2RestTemplate(clientCredentialsResourceDetails());
}
}
也可以仅使用 @EnableOAuth2Client 简化配置。
在客户端开启资源服务,Spring Security 提供了认证过滤器,可对URL进行开放和拦截。
@Configuration
@EnableResourceServer//开启资源服务
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfigurer extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/student").permitAll();
}
}
三.测试
配置完成后,我们可以通过 postMan 或者在浏览器上访问以下链接获取 Token
http://localhost:8763/oauth/token?username=123&password=123&grant_type=password&scope=server&client_id=client-service&client_secret=123456
携带 Token 即可访问受保护的资源
http://localhost:8762/hi?access_token=7e664c6b-b60f-4f1a-97c2-9dea092044c4
我的 Github:Github
CSDN : CSDN 博客
个人网站: 天狼星的博客
完整代码:Spring Cloud Finchley | Spring Cloud OAuth2
微信公众号:[Mr sirius]
参考<<深入理解Spring Cloud 与微服务构建>>