回顾:oauth2和 spring cloud alibaba gateway 整合

一、oauth2认证中心:登录用户进行认证,生成token, 同时定义受保护的api服务

(一)oauth2的四种认证模式:授权码模式,简化模式,密码模式,客户端模式。其中授权码模式和密码模式用的最多。

      A.OAuth2授权码模式: 我们进入一些第三方应用程序时,无需注册,只需要微信授权登录即可,对于我们的服务不需要存储用户的密码,只要存储认证平台返回的唯一ID和用户信息即可,这就是OAuth2常见的授权码模式,它的特点就是:利用第三方权威平台实现用户身份的认证,当然如果我们的公司里面很多微服务,我们自己也可以专门提取出一个认证中心,这个认证中心就是上面说的权威认证平台的角色,所有的微服务均要到这个认证中心做认证,从而实现了单点登录的功能。

     B、OAuth2密码模式:通过用户账号和密码的输入,到认证中心获取到token,这个token就是标识用户的身份,一个网站平台或者一个APP,它可能有多个微服务组成,有了这个token后,在一段时间内可以任意访问这些微服务提供的相关api接口服务。

(二)常见的系统架构: 认证中心、微服务、客户端(app/web程序等终端)

     客户端:通常就是指应用程序,可能是web或者手机app。

     认证中心:OAuth2做账号认证生成token,这个token可以分两种:jwt token放在Header中,或者普通token放在redis中,当然OAuth2还可以当资源鉴权功能。

     应用服务:即各个微服务,统一由认证中心做认证与api访问授权。

四、如何开发OAuth2认证中心(即认证服务端)功能:验证账号与密码、生成并存储token、检查token、刷新token等工作。

    (1)pom.xml引入spring-cloud-starter-oauth2包,这个包中已经有了spring-cloud-starter-security,所以不需要再单独引入spring-cloud-starter-security。

    (2)配置application.yml:主要redis和数据库的配置,OAuth2的一些表需要用到,例如客户端的配置表(oauth_client_details)。

    (3)配置spring security:主要配置BCryptPasswordEncoder密码加密工具和忽略oauth2本身的api的拦截的内容。

            很多人这个地方会疑惑为什么OAuth2还需要spring security(主要是这个WebSecurityConfigurerAdapter )

                 答:这是因为OAuth2本身也同时是一个资源服务(它要对外暴露检查token的接口等),这就需要引入spring security

 对授权服务本身的资源(即OAuth2本身的一些api) 进行保护,即OAuth2要开放哪些api。通过spring security(它的WebSecurityConfigurerAdapter )和oauth2的互相配合对不同的url进行访问的控制,通常在WebSecurityConfigurerAdapter 的类中WebSecurity可以配置一些忽略拦截的url的定义。

         很多人这个地方还有一个疑惑有了spring security的WebSecurityConfigurerAdapter ,为什么还需要OAuth2的ResourceServerConfigurerAdapter?

              答:WebSecurityConfigurerAdapter主要作用于用户的登录(form login,Basic auth),oauth的一些资源不需要拦截(这个不需要OAuth2保护的url),即设置忽略拦截的url定义,通常就是忽略OAuth2服务自身的一些api 接口的一些定义。

                      ResourceServerConfigurerAdapter: OAuth2保护一些微服务的资源,这些资源需要token验证后才能访问,主要是对client和token的认证。                     

                     ResourceServerConfigurerAdapter优先级高: 如果同时设置了对某一资源的访问控制,会以ResourceServerConfigurerAdapter设置的为准,因为ResourceServerConfigurerAdapter优先级更高,他会优先处理,而WebSecurityConfigurerAdapter会失效

     (4) UserDetailsService的代码实现               

                  核心的覆盖重写实现接口中loadUserByUsername方法,这个覆盖实现主要调用系统管理微服务中的用户api服务获取用户,或者验证用户的,一般与数据库的用户账号表密切关联。  

       (5) 编写AuthServerConfig配置类:

                     主要实现三个configure方法的重写,各个方法中主要对应以下即

                       AuthorizationServerEndpointsConfigurer参数的重写:让它支持password模式,设置用户验证服务,token的redis存储方式等。

       ClientDetailsServiceConfigurer参数的重写:定义各个客户端的约束条件。

                     public void configure(AuthorizationServerSecurityConfigurer方法的重写:限制客户端对认证接口的访问权限。

/**
 * 定义授权和令牌端点以及令牌服务
 */
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
{
    endpoints
            // 请求方式
            .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
            // 指定token存储位置
            .tokenStore(tokenStore())
            // 自定义生成令牌
            .tokenEnhancer(tokenEnhancer)
            // 用户账号密码认证
            .userDetailsService(userDetailsService)
            // 指定认证管理器
            .authenticationManager(authenticationManager)
            // 是否重复使用 refresh_token
            .reuseRefreshTokens(false)
            // 自定义异常处理
            .exceptionTranslator(new CustomWebResponseExceptionTranslator());
}
/**
 * 配置令牌端点(Token Endpoint)的安全约束
 */
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
{
    oauthServer.allowFormAuthenticationForClients().checkTokenAccess("permitAll()");
}
/**
 * 配置客户端详情
 */
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception
{
    clients.withClientDetails(clientDetailsService());
}

   (6)token可以分来两种: jwt token和redisToken两种方案,根据需要选择,我推荐采用redisToken,jwtToken还需要设置一些配置类,同时配置到认证服务的端点上。     

 

二、spring cloud gateway集成oauth2的支持,实现:网关服务、负责请求转发和鉴权功能

主要工作两块:

1.nacos中对于网关服务配置各个微服务的路由转向:

spring:
  redis:
    host: localhost
    port: 6379
    password: 123456
  cloud:
    gateway:
      discovery:
        locator:
          lowerCaseServiceId: true
          enabled: true
      routes:
        # 认证中心 ,id在全部路由定义中须要惟一,不能重复
        - id: ebyte-auth
          # lb代表从注册中心获取服务,且已负载均衡方式转发
          uri: lb://ebyte-auth
          # 转发规则定义/oauth/**请求都还转发至微服务ebyte-auth
          predicates:
            - Path=/oauth/**
          filters:
            # 自定义验证码处理过滤器
            - ValidateCodeFilter
            # StripPrefix去除掉上面path的第一个前缀,这个前缀更多是前端的api中定义的(前缀加了微服务的名称),和后端的api不符合
            - StripPrefix=1
        # 系统模块
        - id: ebyte-system
          uri: lb://ebyte-system
          predicates:
            - Path=/system/**
          filters:
            - StripPrefix=1

2.定义一些过滤器(结合业务实际,例如权限的控制,验证码等)。

 

3.其它一些相关知识:


 

在网关集成Oauth2.0后,我们的流程架构如上。主要逻辑如下:
1、客户端应用通过api网关请求认证服务器获取access_token http://localhost:8090/auth-service/oauth/token
2、认证服务器返回access_token

{
  "access_token": "f938d0c1-9633-460d-acdd-f0693a6b5f4c",
  "token_type": "bearer",
  "refresh_token": "4baea735-3c0d-4dfd-b826-91c6772a0962",
  "expires_in": 43199,
  "scope": "web"
}

3、客户端携带access_token通过API网关访问后端服务
file

4、API网关收到access_token后通过 AuthenticationWebFilter 对access_token认证

5、API网关转发后端请求,后端服务请求Oauth2认证服务器获取当前用户

另外:

典型的授权码模式:

  1. 第三方应用向资源持有者请求获取资源
  2. 资源持有者授权给予第三方应用一个许可
  3. 第三方应用将该许可给予认证服务器进行认证,如果认证成功,返回一个Access Token
  4. 第三方应用使用该access token到资源服务器处获取该access token对应的资源(也就是第一步中资源持有者自身的资源)

 

三、spring cloud gateway集成kaptcha图形验证码(后来我改用了第三包easy-captcha的验证码生成包,更省事效果更佳

  步骤1:pom.xml中引入kaptcha包的引用.

  步骤2:定义CaptchaConfig配置类,设置kaptcha图形验证码样式以及生成规则(可以配置自定义的文本的生成器KaptchaTextCreator类)

  步骤3: 定义ValidateCodeHandler, 即验证码的生成

  步骤4:最终的核心就是定义spring cloud gateway的路由配置类RouterFunctionConfiguration,主要把上面的验证码Hander(ValidateCodeHandler)加到路由上来,例如:

/**
 * 路由配置信息
 * 
 * @author zhongzk
 */
@Configuration
public class RouterFunctionConfiguration
{
    @Autowired
    private HystrixFallbackHandler hystrixFallbackHandler;

    @Autowired
    private ValidateCodeHandler imageCodeHandler;

    @SuppressWarnings("rawtypes")
    @Bean
    public RouterFunction routerFunction()
    {
        return RouterFunctions
                .route(RequestPredicates.path("/fallback").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                        hystrixFallbackHandler)
                .andRoute(RequestPredicates.GET("/code").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
                        imageCodeHandler);
    }

}

 

步骤5: 前端通过访问url  http://ip:port/code  返回图形验证码,例如在vue中这样定义:

(1)api文件中定义:

// 获取验证码

export function getCodeImg() {
  return request({
    url: '/code',
    method: 'get'
  })
}

(2)登录页面定义:

<div class="login-code">
  <img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
methods: {
  getCode() {
    getCodeImg().then(res => {
      this.codeUrl = "data:image/gif;base64," + res.img;
      this.loginForm.uuid = res.uuid;
    });
  },

 

后端的生成验证码的api定义:

/**
 * 生成验证码
 */
@Override
public AjaxResult createCapcha() throws IOException, CaptchaException
{
    // 生成验证码
    String capText = producer.createText();
    String capStr = capText.substring(0, capText.lastIndexOf("@"));
    String verifyCode = capText.substring(capText.lastIndexOf("@") + 1);
    BufferedImage image = producer.createImage(capStr);
    // 保存验证码信息
    String uuid = IdUtils.simpleUUID();
    String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;

    System.out.println("验证码:" + verifyKey);

    redisService.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
    // 转换流信息写出
    FastByteArrayOutputStream os = new FastByteArrayOutputStream();
    try
    {
        ImageIO.write(image, "jpg", os);
    }
    catch (IOException e)
    {
        return AjaxResult.error(e.getMessage());
    }

    AjaxResult ajax = AjaxResult.success();
    ajax.put("uuid", uuid);
    ajax.put("img", Base64.encode(os.toByteArray()));
    return ajax;
}

 

 

 

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值