网关安全(二)-OAuth2协议简介与认证服务器搭建

1、OAuth2协议中的角色流程概要介绍

OAuth2协议主要使用来认证和授权的,我们先来看一下OAuth2协议中的角色

  1.1、用户:真正的人,大家都有可能是某一个服务的用户。

  1.2、客户端应用:Web或手机App,直接跟用户打交道的。通过客户端应用发http请求,访问服务。

  1.3、认证服务器:作用就是认证,验证用户身份发出令牌。

  1.4、资源服务器:在这里代表各个微服务。一个认证服务器可以对应多个资源服务器。

  大概的流程是:用户直接访问客户端应用,客户端首先要去认证服务器认证,验证要访问微服务用户的真实性,认证服务器确认用户身份后,会发出一个代表用户身份的令牌给客户端应用,客户端应用就会拿着令牌去访问资源服务器(我们的微服务),资源服务器会去认证服务器验证这个令牌是谁。

2、部分角色准备

  2.1、用户,就是我们自己。

  2.2、客户端应用:http请求工具,可以是Restlet Client、Postman等。

  2.3、资源服务器,我们准备两个简单的微服务,一个订单服务,一个价格服务,订单服务调用价格服务获取价格。

    2.3.1、订单服务,端口9080

    2.3.2、价格服务,端口9070

3、搭建认证服务器

  3.1、项目结构

   3.2、pom.xml导入spring-cloud-starter-oauth2依赖

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>
    </dependencies>

  3.3、OAuth2AuthServerConfig,认证服务器配置

/**
 * OAuth2认证服务器配置类
 * 需要继承AuthorizationServerConfigurerAdapter类,覆盖里面三个configure方法
 * 并添加@EnableAuthorizationServer注解,指定当前应用做为认证服务器
 *
 * @author caofanqi
 * @date 2020/1/31 18:04
 */
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {


    @Resource
    private AuthenticationManager authenticationManager;


    /**
     * 配置授权服务器的安全性
     * checkTokenAccess:验证令牌需要什么条件,isAuthenticated():需要经过身份认证。
     * 此处的passwordEncoders是为client secrets配置的。
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("isAuthenticated()").passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 配置客户端服务
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients
                //配置在内存中
                .inMemory()
                //客户端应用的用户名
                .withClient("webApp")
                //客户端应用加密过的密码
                .secret(new BCryptPasswordEncoder().encode("123456"))
                //orderApp可以获取所有的权限集合,用于做ACL的权限控制
                .scopes("read", "write")
                //发出去令牌的有效期,单位秒
                .accessTokenValiditySeconds(3600)
                //可以访问哪些资源服务器
                .resourceIds("order-server")
                //授权的方式
                .authorizedGrantTypes("password")
                .and()
                //订单服务要访问资源服务器验证令牌,所以也需要配置相关信息
                .withClient("orderService")
                .secret(new BCryptPasswordEncoder().encode("123456"))
                .scopes("read", "write")
                .accessTokenValiditySeconds(3600)
                .resourceIds("order-server")
                .authorizedGrantTypes("password");

    }

    /**
     * 配置授权服务器终端的非安全特征
     * authenticationManager 校验用户信息是否合法
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }

}

  3.4、WebSecurityConfig,安全配置

/**
 * WebSecurity安全配置
 *
 * @author caofanqi
 * @date 2020/1/31 22:48
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /**
     * AuthenticationManagerBuilder可以帮助我们构建出一个AuthenticationManager,需要UserDetailsService和PasswordEncoder
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }


    /**
     * 将AuthenticationManager暴露成Bean
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}

  3.5、UserDetailsService

/**
 * 查询用户信息
 * @author caofanqi
 * @date 2020/2/1 3:41
 */
@Component
public class UserDetailsServiceImpl implements UserDetailsService {


    /**
     *  此处为了简便,没有连接数据库,不管什么用户名,只要密码是123456就会通过验证
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return User.withUsername(username)
                .password(new BCryptPasswordEncoder().encode("123456"))
                .authorities("ROLE_ADMIN").build();
    }

}

  3.6、启动项目,端口9020,看控制台有三个路径,/oauth/token获取token,/oauth/token_key,/oauth/check_token用于校验token

   3.7、测试密码模式获取令牌

    3.7.1、请求路径:http://127.0.0.1:9020/oauth/token

    3.7.2、使用httpBasic添加客户端认证信息

    3.7.3、表单添加用户信息,username(用户名)、password(密码)、grant_type(授权模式)、scope(权限范围)

  3.7.4、返回值,access_token(令牌)、token_type(令牌类型)、expires_in(有效期剩余时间)、scope(权限范围)。

 

项目源码:https://github.com/caofanqi/study-security/tree/dev-AuthorizationServer

posted @ 2020-02-01 15:54  caofanqi  阅读(1419)  评论(0编辑  收藏  举报