Oauth2
oauth2采用令牌的方式让用户灵活地对第三方应用授权访问资源或者撤销权限
授权流程
- 客户端像用户请求授权
- 用户同意后服务器返回一个授权凭证
- 客户端可以拿着凭证访问授权服务器,申请令牌
- 授权服务器确认无误后,发放令牌
- 客户端可以拿着令牌访问资源服务器上的资源
- 资源服务器确认后发放资源
授权模式有四种:
- 授权码模式:最完整,最严谨,第三方登录基本使用这种模式
- 简化模式:不需要客户端参与,直接在浏览器中向授权服务器申请令牌
- 密码模式:用户直接把用户名密码告诉客户端,客户端根据这些信息申请令牌
- 客户端模式:客户端以自己的名义向授权服务器申请令牌
案例
添加依赖
- web
- redis
- springsecurity
- oauth2
第一步:配置redis服务器
# 配置redis
spring.redis.database=0
spring.redis.host=39.105.34.128
spring.redis.port=6379
spring.redis.password=123456
第二步:配置 授权服务器
继承AuthorizationServerConfigurerAdapter类,@EnableAuthorizationServer注解开启授权服务器
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
AuthenticationManager authenticationManager; //支持password模式
@Autowired
RedisConnectionFactory redisConnectionFactory;//完成令牌在redis的缓存
@Autowired
UserDetailsService userDetailsService; //支持刷新token
@Bean
PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(); //加密
}
/**
* 配置授权模式
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("password")//授权模式
.authorizedGrantTypes("password","refresh_token") //两种授权模式,refresh_token用来刷新令牌
.accessTokenValiditySeconds(1800) //令牌过期时间
.resourceIds("rid") //资源id
.scopes("all")
.secret("$2a$10$iLjByvwNFoXRYShm9FwpmOQIoF6v6PAPhbGGVjkHtAFpbATvi4BuO");//明文123
}
/**
* 配置了令牌的存储,授权模式,令牌刷新
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(new RedisTokenStore(redisConnectionFactory))
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
/**
* 表示支持client_id & client_secret做认证
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients();
}
}
第三步:配置资源服务器
继承ResourceServerConfigurerAdapter,@EnableResourceServer注解表示开启资源服务器
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("rid") //与授权服务器配置的id相同
.stateless(true); //仅基于令牌认证
}
/**
* 配置路由规则
* @param http
* @throws Exception
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
.anyRequest().authenticated();
}
}
第四步:配置Security
提供必须的Bean,以及配置用户信息,路由信息(这里的路由信息优先级高于资源服务器的路由信息)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//提供给授权服务器
@Override
@Bean
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
//提供给授权服务器
@Override
@Bean
protected UserDetailsService userDetailsService(){
return super.userDetailsService();
}
//配置用户角色信息
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("panlijie").password("$2a$10$iLjByvwNFoXRYShm9FwpmOQIoF6v6PAPhbGGVjkHtAFpbATvi4BuO")
.roles("admin")
.and()
.withUser("suyanxia").password("$2a$10$iLjByvwNFoXRYShm9FwpmOQIoF6v6PAPhbGGVjkHtAFpbATvi4BuO")
.roles("user");
}
//路由规则
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/oauth/**")
.authorizeRequests()
.antMatchers("/oauth/**")
.permitAll()
.and()
.csrf().disable();
}
}
第五步:PostMan测试
post提交申请令牌
根据令牌获取资源:
⛏定