统一认证中心 Oauth2 认证坑

简介: 统一认证Oauth2的认证完美填坑
cas-server-url: http://cas-server-service #这里配置成HA地址

security:
  oauth2: #与cas-server对应的配置
    client:
      client-id: admin-web
      client-secret: admin-web-123
      user-authorization-uri: ${cas-server-url}/oauth/authorize #是授权码认证方式需要的
      access-token-uri: ${cas-server-url}/oauth/token #是密码模式需要用到的获取 token 的接口
    resource:
      loadBalanced: true
      id: admin-web
      user-info-uri: ${cas-server-url}/api/user #指定user info的URI
      prefer-token-info: false

这里的 url 配置是基于k8s的 Service,实现负载均衡,从而实现高可用。但我们接下来分析 user-info-uri。user-info-uri 的原理是在授权服务器认证后将认证信息 Principal 通过形参绑定的方法通过URL的方式获取用户信息。当然它也有配套的 UserInfoTokenService 等。

但这个在客户端获取用户权限时候,是存在一定问题的。譬如 Web端请求消费端的某个接口:

/**
 * 返回发现的所有服务
 * @author Damon 
 * @date 2021年11月2日 下午8:18:44
 * @return
 *
 */
@PreAuthorize("hasRole('admin')")
    @GetMapping(value = "/getService")
    public String getService(){
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> formEntity = new HttpEntity<String>(null, headers);
        String body = "";
        try {
            ResponseEntity<String> responseEntity = restTemplate.exchange("http://cas-server/api/v1/user",
                    HttpMethod.GET, formEntity, String.class);
            if (responseEntity.getStatusCodeValue() == 200) {
                return "ok";
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return body;
    }

在这个接口中,我们通过添加@PreAuthorize("hasRole('admin')")来控制权限,只要是admin的用户才能访问改接口。

我们先来请求认证中心登录接口,获取token:

image.png

在拿到token之后,我们请求这个接口,我们会发现:

image.png

说明未认证,我们再看看:发现原来当请求这个接口时,消费端后去请求认证中心的接口:

2021-11-03 15:59:09.385 DEBUG 127896 --- [io2-2001-exec-4] org.springframework.web.HttpLogging      : HTTP GET http://cas-server/auth/user
2021-11-03 15:59:09.389 DEBUG 127896 --- [io2-2001-exec-4] org.springframework.web.HttpLogging      : Accept=[application/json, application/*+json]
2021-11-03 15:59:09.427 DEBUG 127896 --- [io2-2001-exec-4] org.springframework.web.HttpLogging      : Response 404 NOT_FOUND
2021-11-03 15:59:09.446 DEBUG 127896 --- [io2-2001-exec-4] o.s.w.c.HttpMessageConverterExtractor    : Reading to [org.springframework.security.oauth2.common.exceptions.OAuth2Exception]
2021-11-03 15:59:09.456  WARN 127896 --- [io2-2001-exec-4] o.s.b.a.s.o.r.UserInfoTokenServices      : Could not fetch user details: class org.springframework.web.client.HttpClientErrorException$NotFound, 404 : [{"timestamp":"2021-11-03T07:59:09.423+00:00","status":404,"error":"Not Found","message":"","path":"/auth/user"}]
2021-11-03 15:59:09.457 ERROR 127896 --- [io2-2001-exec-4] c.l.h.CustomAuthenticationEntryPoint     : 无效的token,请重新认证访问
{"data":"b34841b4-61fa-4dbb-9e2b-76496deb27b4","result":{"code":20202,"msg":"未认证","status":401}}

但认证中心给返回的404状态码,此时会走统一异常EntryPoint提示报错:无效的token,请重新认证访问。从而返回信息体:{"data":"b34841b4-61fa-4dbb-9e2b-76496deb27b4","result":{"code":20202,"msg":"未认证","status":401}}

接下来分析:为什么认证中心会返回404呢?看认证中心日志:

2021-11-03 15:59:09.407 DEBUG 54492 --- [o2-2000-exec-15] o.s.web.servlet.DispatcherServlet        : GET "/auth/user", parameters={}
2021-11-03 15:59:09.409 DEBUG 54492 --- [o2-2000-exec-15] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"]
2021-11-03 15:59:09.413 DEBUG 54492 --- [o2-2000-exec-15] o.s.w.s.r.ResourceHttpRequestHandler     : Resource not found
2021-11-03 15:59:09.414 DEBUG 54492 --- [o2-2000-exec-15] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND
2021-11-03 15:59:09.422 DEBUG 54492 --- [o2-2000-exec-15] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}
2021-11-03 15:59:09.423 DEBUG 54492 --- [o2-2000-exec-15] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2021-11-03 15:59:09.424 DEBUG 54492 --- [o2-2000-exec-15] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [application/json] and supported [application/json, application/*+json, application/json, application/*+json, application/json, application/*+json]
2021-11-03 15:59:09.424 DEBUG 54492 --- [o2-2000-exec-15] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [{timestamp=Wed Nov 03 15:59:09 CST 2021, status=404, error=Not Found, message=, path=/auth/user}]
2021-11-03 15:59:09.426 DEBUG 54492 --- [o2-2000-exec-15] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 404

发现原来Oauth2没有此类接口:/auth/user。最后决定自写一个接口来替换原生:

@GetMapping("/api/v1/user")
    public Authentication user(Map map, Principal user, Authentication auth) {
        //获取当前用户信息
        logger.info("cas-server provide user: " + JSON.toJSONString(auth));
        return auth;
    }

在封装、覆盖后,在消费端直接配置相关配置:

cas-server-url: http://cas-server

security:
  path:
    ignores: /,/index,/static/**,/css/**, /image/**, /favicon.ico, /js/**,/plugin/**,/avue.min.js,/img/**,/fonts/**
  oauth2:
    client:
      client-id: rest-service
      client-secret: rest-service-123
      user-authorization-uri: ${cas-server-url}/oauth/authorize
      access-token-uri: ${cas-server-url}/oauth/token
    resource:
      loadBalanced: true
      id: rest-service
      prefer-token-info: false
      user-info-uri: ${cas-server-url}/api/v1/user
    authorization:
      check-token-access: ${cas-server-url}/oauth/check_token

同时启动认证中心、消费端,继续获取token后,请求接口:

image.png

此时,发现是403,没有权限了,这下我们可以对用户添加这种权限即可:

"authorities": [ { "authority": "ROLE_admin" }, { "authority": "admin" }

添加完之后,我们发现可以请求接口成功:

{ "authorities": [ { "authority": "ROLE_admin" }, { "authority": "admin" } ], "details": { "remoteAddress": "0:0:0:0:0:0:0:1", "sessionId": null, "tokenValue": "b34841b4-61fa-4dbb-9e2b-76496deb27b4", "tokenType": "bearer", "decodedDetails": null }, "authenticated": true, "userAuthentication": { "authorities": [ { "authority": "ROLE_admin" }, { "authority": "admin" } ], "details": { "authorities": [ { "authority": "ROLE_admin" }, { "authority": "admin" } ], "details": { "remoteAddress": "169.254.200.12", "sessionId": null, "tokenValue": "b34841b4-61fa-4dbb-9e2b-76496deb27b4", "tokenType": "Bearer", "decodedDetails": null }, "authenticated": true, "userAuthentication": { "authorities": [ { "authority": "ROLE_admin" }, { "authority": "admin" } ],
...

这里简单测试,直接写的返回当前用户权限的接口,发现权限就是"ROLE_admin、"admin"。

总结

有时候官网的源码解析很少,我们必须看源码,结合实际行动才能准确的分析其用意。所以当其不存在、或者不满足我们的需求时,可以选择覆盖其源码逻辑,实现自定义模式,这样会避免很多不必要的麻烦。因为源码解析毕竟不同版本,对应的源码也是不同的。

相关文章
针对FastAdmin新增上传多个图片,新增上传的视频的预览效果
针对FastAdmin新增上传多个图片,新增上传的视频的预览效果
1261 0
|
安全 Shell Linux
【Shell 命令集合 文件管理】Linux ssh 远程主机之间复制文件 scp 命令使用教程
【Shell 命令集合 文件管理】Linux ssh 远程主机之间复制文件 scp 命令使用教程
737 0
|
存储 安全 Java
Spring Security Oauth2 之 密码模式请求/oauth/token 解析
前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger 种一棵树最好的时间是十年前,其次是现在
2076 0
|
12月前
|
存储 运维 Cloud Native
数据仓库革新:Snowflake在云数据平台中的创新实践
【10月更文挑战第26天】随着大数据时代的到来,数据仓库正经历重大变革。本文探讨了Snowflake在云数据平台中的创新应用,通过弹性扩展、高性能查询、数据安全、多数据源接入和云原生架构等最佳实践,展示了其独特优势,帮助企业提升数据处理和分析效率,保障数据安全,降低运维成本,推动业务快速发展。
517 2
|
存储 数据安全/隐私保护 开发者
SpringSecurity+OAuth2.0 搭建认证中心和资源服务中心
OAuth 2.0(开放授权 2.0)是一个开放标准,用于授权第三方应用程序访问用户在资源所有者(用户)的帐户上存储的受保护资源,而无需共享用户凭据。OAuth 2.0 主要用于在互联网上安全地委托授权,广泛应用于身份验证和授权场景。
2116 1
|
SQL 存储 关系型数据库
SQL安装实战:从零开始,一步步掌握SQL数据库的安装与配置
配置SQL数据库以优化性能 安装完成后,接下来的任务是对SQL数据库进行必要的配置,以确保其能够顺利运行并满足你的性能需求。以下是一些关键的配置步骤:
|
Java 应用服务中间件 Android开发
【Eclipse IDEA】IDEA 导入 eclipse Web项目
【Eclipse IDEA】IDEA 导入 eclipse Web项目
|
前端开发 Java 开发者
每天一个摆脱if-else工程师的技巧,优雅的参数校验
在日常的开发工作中,为了程序的健壮性,大部分方法都需要进行入参数据校验。本文围绕作者如何优雅的进行参数校验展开讨论。
122619 9
|
SpringCloudAlibaba 前端开发 安全
SpringCloud Alibaba实战二十六 - Oauth2认证服务器自定义异常
SpringCloud Alibaba实战二十六 - Oauth2认证服务器自定义异常
698 0
|
前端开发 JavaScript Java
Springboot用官方建议访问Html页面并接传值
特别强调:启动类和所有的controller service mapper等包必须位于同一个主包下(同一个包中),而且启动类在最外面,否则这些层都扫不到,不报错,但是无法实现我们的功能,要非常注意 我们以前通常习惯用webapp来放置jsp页面,但是到...
3811 0