OAuth2简介

参考微服务统⼀认证⽅案
OAuth 2.0是用于授权的行业标准协议。OAuth 2.0为简化客户端开发提供了特定的授权流,包括Web应用、桌面应用、移动端应用等。使用OAuth2 认证的好处就是你只需要一个账号密码,就能在各个网站进行访问,而面去了在每个网站都进行注册的繁琐过程,如:很多网站都可以使用微信登录,网站作为第三方服务、微信作为服务提供商.

OAuth2角色

  • Resource owner(资源拥有者):拥有该资源的最终用户,他有访问资源的账号密码;
  • Resource server(资源服务器):拥有受保护资源的服务器,如果请求包含正确的访问令牌,可以访问资源;
  • Client(客户端):访问资源的客户端,会使用访问令牌去获取资源服务器的资源,可以是浏览器、移动设备或者服务器;
  • Authorization server(授权服务器):用于认证用户的服务器,如果客户端认证通过,发放访问资源服务器的令牌。

授权模式

  • Authorization Code(授权码模式):是功能最完整、流程最严密的授权模式,客户端先将用户导向认证服务器,登录后获取授权码,然后进行授权,最后根据授权码获取访问令牌;
  • Resource Owner Password Credentials(密码模式):客户端直接向用户获取用户名和密码,之后向认证服务器获取访问令牌;
  • Implicit(简化模式):和授权码模式相比,取消了获取授权码的过程,直接获取访问令牌;
  • Client Credentials(客户端模式):客户端直接通过客户端认证(比如client_id和client_secret)从认证服务器获取访问令牌。

配置类AuthorizationServerConfigurerAdapter

@EnableAuthorizationServer	//为微服务运行环境提供一个基于 OAuth2 协议的授权服务
public class config extends AuthorizationServerConfigurerAdapter {
    @Override	//用来配置令牌端点(Token Endpoint)的安全约束
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        super.configure(security);
    }

    @Override	//配置客户端详情
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        super.configure(clients);
    }

    @Override	//用来配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        super.configure(endpoints);
    }
}

1. 配置客户端详情(Client Details)

能够使用内存或 JDBC 方式实现获取已注册的客户端详情,有几个重要的属性:

  • withClient:客户端标识 ID
  • secret:客户端安全码
  • scope:客户端访问范围,默认为空则拥有全部范围
  • authorizedGrantTypes:客户端使用的授权类型,默认为空
  • authorities:客户端可使用的权限
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("admin-app")
                .secret(passwordEncoder.encode("123456"))
                .scopes("all")
                .authorizedGrantTypes("password", "refresh_token")
                .accessTokenValiditySeconds(3600*24)
                .refreshTokenValiditySeconds(3600*24*7)
                .and()
                .withClient("portal-app")
                .secret(passwordEncoder.encode("123456"))
                .scopes("all")
                .authorizedGrantTypes("password", "refresh_token")
                .accessTokenValiditySeconds(3600*24)
                .refreshTokenValiditySeconds(3600*24*7);
    }

2. 配置令牌管理(EndpointsConfigurer)

JwtAccessTokenConverter是用来生成token的转换器,而token令牌默认是有签名的,且资源服务器需要验证这个签名。此处的加密及验签包括两种方式:对称加密、非对称加密(公钥密钥).对称加密需要授权服务器和资源服务器存储同一key值,而非对称加密可使用密钥加密,暴露公钥给资源服务器验签.

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authenticationManager(authenticationManager)
                // 配置JwtAccessToken转换器
                .accessTokenConverter(jwtAccessTokenConverter())
                // refresh_token需要userDetailsService
                .reuseRefreshTokens(false)
		//配置加载用户信息的服务;
		.userDetailsService(userDetailsService)
    }

      //使用非对称加密算法来对Token进行签名
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {

        final JwtAccessTokenConverter converter = new JwtAccessToken();
        // 导入证书
        KeyStoreKeyFactory keyStoreKeyFactory =
                new KeyStoreKeyFactory(new ClassPathResource("keystore.jks"), "mypass".toCharArray());
        converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));

        return converter;
    }

3. 配置安全规则(SecurityConfigurer)

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        oauthServer
                // 开启/oauth/token_key验证端口无权限访问
                .tokenKeyAccess("permitAll()")
                // 开启/oauth/check_token验证端口认证权限访问
                .checkTokenAccess("isAuthenticated()");
    }

Q.E.D.