看完oauth2,随手总结

254 阅读4分钟

1.四种授权方式(简化模式省略)

授权码模式(authorization code)

  1. 资源拥有者访问客户端,客户端要求资源拥有者授权(浏览器重定向到授权服务器,并携带着客户端本身的信息,这里要求客户端本身要在授权服务器中有记录)。

  2. 浏览器出现授权服务器授权页面,用户授权。 /uaa/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com

  3. 授权服务器在经过用户同意授权之后,将授权码转经浏览器(就是在客户端配置的返回的重定向url地址,redirect_uri)返回给客户端

  4. 客户端拿着授权码 再次向授权服务器索要access_token。

/uaa/oauth/token?client_id=c1&client_secret=secret&grant_type=authorization_code&code=5PgfcD &redirect_uri=http://www.baidu.com

虽然过程是四种中最复杂的,但也是最安全的,为了安全不在乎这些性能损耗和逻辑。其实逻辑也还好。

密码模式

资源拥有者将用户名和密码 发送给客户端,客户端拿着用户名和密码向资源服务器请求令牌(access_token)。

适用范围:既然将用户名和密码 交给了客户端,那么就意味着风险。所以该方法适用于我们自己开发的客户端。

客户端模式

拿着客户端id+访问类型,就可以直接获取访问令牌。

前提是:非常信任这个客户端

授权码模式配置

授权码用的最多,这边详细说一下授权码的配置。

授权服务器 继承AuthorizationServerConfigurerAdapter

@Configuration
@EnableAuthorizationServer //声明是资源授权服务器
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
    //这边三个配置 配置具体内容 查看父类
   public class AuthorizationServerConfigurerAdapter implements AuthorizationServerConfigurer { 

       //配置客户端信息
       @Override
       public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
       }

       //配置授权服务器 令牌访问端点和令牌服务
       @Override
       public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
       }

       //配置令牌端点约束,哪些可以通过,哪些要拦截
       @Override
       public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
       }

}

捞一下别人的写好的代码。

@Configuration
@EnableAuthorizationServer
public class OauthServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    private DataSource dataSource; //注入application.yml中配置的数据源
    @Autowired
    private AuthenticationManager authenticationManager; //认证管理器

    @Autowired
    private UserDetailsService userDetailsService; //查询数据库

    //从数据库中查询出客户端信息
    @Bean
    public JdbcClientDetailsService clientDetailsService() {
        return new JdbcClientDetailsService(dataSource);
    }

    //token保存策略 (有基于内存的(InMemoryTokenStore),有基于数据库的(JdbcTokenStore),还有个最牛逼的jwt(JwtTokenStore)
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

    //授权信息保存策略
    @Bean
    public ApprovalStore approvalStore() {
        return new JdbcApprovalStore(dataSource);
    }

    //授权码模式专用对象
    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        return new JdbcAuthorizationCodeServices(dataSource); 
    }

    //指定客户端登录信息来源
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService());
    }
    
    //配置 令牌端点约束
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.allowFormAuthenticationForClients();
        oauthServer.checkTokenAccess("isAuthenticated()"); // /oauth/check_token安全配置地址 将checkTokenAccess完全放开,所有人都可以访问。
    }
    
    //配置 令牌端点和令牌服务
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
        .approvalStore(approvalStore())
        .authenticationManager(authenticationManager) //匹配 密码服务的
        .authorizationCodeServices(authorizationCodeServices()) //匹配 授权码服务的
        .tokenStore(tokenStore());
    }

资源服务器配置

和上面的一样。开启资源服务注解@EnableResourceServer,和继承资源服务器配置适配器ResourceServerConfigurerAdapter,并实现其中的两个方法。

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResouceServerConfig extends ResourceServerConfigurerAdapter {

   public static final String RESOURCE_ID = "res1";
   
   //资源服务令牌解析服务,远程调用授权服务中接口去 验证token。 加了这个才是完整的授权服务!!
   @Bean
   public ResourceServerTokenServices tokenService() {
       //使用远程服务请求授权服务器校验token,必须指定校验token 的url、client_id,client_secret
       RemoteTokenServices service=new RemoteTokenServices();
       service.setCheckTokenEndpointUrl("http://localhost:53020/uaa/oauth/check_token");
       service.setClientId("c1");
       service.setClientSecret("secret");
       return service;
   }
   
   /**
    * tokenServices: ResourceServerTokenServices 类的实例,用来实现令牌服务
    * resourceId: 资源服务的id
    * tokenStore: token存储策略,指定令牌从哪获取,是jwt呢,还是数据库,还是内存。
    */
   @Override
   public void configure(ResourceServerSecurityConfigurer resources) {
       resources.resourceId(RESOURCE_ID)
       .tokenServices(tokenService())
       .stateless(true);
   }
   
    /**
     * HttpSecurity配置这个与Spring Security类似:
     * 请求匹配器,用来设置需要进行保护的资源路径,默认的情况下是保护资源服务的全部路径。
     * 通过http.authorizeRequests()来设置受保护资源的访问规则
     * 其他的自定义权限保护规则通过 HttpSecurity 来进行配置。
     */
   @Override
   public void configure(HttpSecurity http) throws Exception {
       http
       .authorizeRequests()
       .antMatchers("/**").access("#oauth2.hasScope('all')")
       .and().csrf().disable()
       .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
   }
}

另外springsecurity中的WebSecurityConfigurerAdapter这个中 protected void configure(HttpSecurity http) throws Exception {}配置安全拦截机制也是非常重要的。