首页 > 其他分享 >微服务集成springsecurity实现认证

微服务集成springsecurity实现认证

时间:2024-07-27 23:07:23浏览次数:16  
标签:集成 return String exchange private 认证 token ServerWebExchange springsecurity

module:auth

1.添加依赖:spring-cloud-starter-security与spring-cloud-starter-oauth2

2.配置WebSecurityConfig:注入AuthenticationManager覆写configure

3.配置tokenConfig

4.授权服务器配置:AuthorizationServer extends AuthorizationServerConfigurerAdapter配置客户端详细任务,令牌端点配置

5.实现UserDetailsService,覆写loadUserByUsername(最熟悉的一集)

tips:这里return 的UserDetails对象不用自己创建,springsecurity提供了一个User类实现了UserDetails,通过建造者模式可以直接生成username,password,authorities等信息。这里如果需要多参数分发给其他module使用,建议的做法是将数据库中查出来的对象通过json转成字符串存入username,后续可以直接将username反写成具体的class

module:gateway

首先明确网关的作用:路由转发、认证、白名单放行:针对当前网关的路由进行转发,如果是白名单则直接放行,如果是需要JWT校验则需要校验JWT合法性

security中提供了认证与授权,这里我们在网关进行了认证,也就是说授权模块是在各个微服务中进行的

gateway集成springsecurity:

1.添加依赖:spring-cloud-starter-security与spring-cloud-starter-oauth2

2.添加配置:过滤器;再添加tokenConfig、securityConfig



/**
*
* @description 网关认证过滤器:这段代码主要是作为过滤器去处理一个http请求,首先是检查请求路径是否在白名单中,请求是否携带token/有没有过期等安全相关检查
*/
@Component @Slf4j public class GatewayAuthFilter implements GlobalFilter, Ordered { //白名单 private static List<String> whitelist = null; static { //加载白名单 try ( InputStream resourceAsStream = GatewayAuthFilter.class.getResourceAsStream("/security-whitelist.properties"); ) { Properties properties = new Properties(); properties.load(resourceAsStream); Set<String> strings = properties.stringPropertyNames(); whitelist= new ArrayList<>(strings); } catch (Exception e) { log.error("加载/security-whitelist.properties出错:{}",e.getMessage()); e.printStackTrace(); } } @Autowired private TokenStore tokenStore; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String requestUrl = exchange.getRequest().getPath().value(); AntPathMatcher pathMatcher = new AntPathMatcher(); //白名单放行 for (String url : whitelist) { if (pathMatcher.match(url, requestUrl)) { return chain.filter(exchange); } } //检查token是否存在 String token = getToken(exchange); if (StringUtils.isBlank(token)) { return buildReturnMono("没有认证",exchange); } //判断是否是有效的token OAuth2AccessToken oAuth2AccessToken; try { oAuth2AccessToken = tokenStore.readAccessToken(token); boolean expired = oAuth2AccessToken.isExpired(); if (expired) { return buildReturnMono("认证令牌已过期",exchange); } return chain.filter(exchange); } catch (InvalidTokenException e) { log.info("认证令牌无效: {}", token); return buildReturnMono("认证令牌无效",exchange); } } /** * 获取token */ private String getToken(ServerWebExchange exchange) { String tokenStr = exchange.getRequest().getHeaders().getFirst("Authorization"); if (StringUtils.isBlank(tokenStr)) { return null; } String token = tokenStr.split(" ")[1]; if (StringUtils.isBlank(token)) { return null; } return token; } private Mono<Void> buildReturnMono(String error, ServerWebExchange exchange) { ServerHttpResponse response = exchange.getResponse(); String jsonString = JSON.toJSONString(new RestErrorResponse(error)); byte[] bits = jsonString.getBytes(StandardCharsets.UTF_8); DataBuffer buffer = response.bufferFactory().wrap(bits); response.setStatusCode(HttpStatus.UNAUTHORIZED); response.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); return response.writeWith(Mono.just(buffer)); } @Override public int getOrder() { return 0; } }

    // 假设已经从请求中获得了token  
    String token = getToken(exchange);  
  
    // 如果token存在且不为空  
    if (token != null && !token.isEmpty()) {  
        // 创建一个新的ServerHttpRequest,并添加token到Authorization头  
        ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()  
                .header("Authorization", "Bearer " + token)
                .build();  
  
        // 使用ServerWebExchangeDecorator来包装原始的ServerWebExchange,并且使用修改后的请求  
        ServerWebExchange mutatedExchange = exchange.mutate()  
                .request(mutatedRequest)  
                .build();  

        return chain.filter(mutatedExchange);  
    }  

3.配置白名单security-whitelist.properties

/media/open/**=媒资管理公开访问接口

4.在其他微服务模块中放行所有路由,并且直接通过SecurityContextHolder.getContext().getAuthentication()获取对象(因为在网关中已经校验完了,这里只负责授权)

module:others

1.包装一个SecurityUtil。SecurityContextHolder.getContext().getAuthentication().getPrincipal();即可获得具体username,然后将username转为实体类即可使用

@Slf4j
public class SecurityUtil {

    public static XcUser getUser() {
        try {
            Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            if (principalObj instanceof String) {
                //取出用户身份信息
                String principal = principalObj.toString();
                //将json转成对象
                XcUser user = JSON.parseObject(principal, XcUser.class);
                return user;
            }
        } catch (Exception e) {
            log.error("获取当前登录用户身份出错:{}", e.getMessage());
            e.printStackTrace();
        }

        return null;
    }


    @Data
    public static class XcUser implements Serializable {

        private static final long serialVersionUID = 1L;

        private String id;

        private String username;

        private String password;

        private String salt;

        private String name;
        private String nickname;
        private String wxUnionid;
        private String companyId;
        /**
         * 头像
         */
        private String userpic;

        private String utype;

        private LocalDateTime birthday;

        private String sex;

        private String email;

        private String cellphone;

        private String qq;

        /**
         * 用户状态
         */
        private String status;

        private LocalDateTime createTime;

        private LocalDateTime updateTime;


    }


}

使用说明:上文使用了成员内部类,XcUser定义在外部类的成员位置,其不能创建独立对象,必须依靠外部类实例.new 内部类()来创建实例

SecurityUtil.XcUser user = SecurityUtil.getUser();

 

Q&A:

token在gateway中传递下去的?

(无oauth2集成)一般情况下我们需要修改ServerWebExchange里的ServerHttpRequest,但是ServerHttpRequest是不可变的。因此如果我们需要添加上token,就需要新建一个ServerWebExchange,重写ServerHttpRequest。

除此以外,因为我们还会将请求传递给下一个GatewayFilterChain,我们可以在这个请求传递的时候通过修改ServerWebExchange的MutableHttpRequest:

(有oauth2集成)springsecurity的过滤器链会自动处理从请求中提取token,并将其附加到上下文中,下游的过滤器会通过springsecurity的API获取他

 

为什么其他微服务模块能直接通过SecurityContextHolder.getContext().getAuthentication()获取对象?

在微服务中,每一个模块都有独属于自己的JVM,拥有独属于自己的线程,也就是说每个模块的SecurityContext是不一样的。当我们使用oauth2,用户通过上述gateway进行认证,并获取一个jwt将其放在request中。

当一个模块接收到一个包含oauth2令牌的http请求时,他会使用这个令牌来验证用户身份,并且基于令牌构建一个新的SecurityContext。也就是说SecurityContext的实现其实是局限于单个服务的单个线程的,跨服务的安全信息传递是由oauth2进行的

标签:集成,return,String,exchange,private,认证,token,ServerWebExchange,springsecurity
From: https://www.cnblogs.com/kun1790051360/p/18324363

相关文章

  • 手把手教你集成GraphRag.Net:打造智能图谱搜索系统
        在人工智能和大数据发展的背景下,我们常常需要在项目中实现知识图谱的应用,以便快速、准确地检索和使用信息。        今天,我将向大家详细介绍如何在一个新的.NET项目中集成GraphRag.Net,这是一个参考GraphRag实现的.NET版本,能够实现图谱数据的存储、检索、和问......
  • Vue3 - 最新详细实现网站接入Google谷歌授权登录配置流程及示例代码教程,手机移动端、p
    前言如果您需要Vue2版本,请访问这篇文章。在vue3|nuxt3网站开发中,详解实现vue3接入新版google谷歌快捷登录教程,电脑PC网站、手机网站集成谷歌授权登录服务及拿到用户个人信息头像邮箱等,国内第三方web站点使用google账号登陆及授权重定向,提供详细的本地调试方法以......
  • STM32开发环境配置记录——关于PlatformIO + VSCode + CubeMX的集成环境配置
    前言​ 为什么配置这样的一个环境呢?鄙人受够了Keil5那个简陋的工作环境了,实在是用不下去,调试上很容易跟CubeMX的代码产生不协调导致调试——发布代码不一致造成的一系列问题。CubeIDE虽说不错,但是它的代码辅助功能和构建系统实在不敢恭维,经常出现Makefile未同步导致符号定义冲突,......
  • jenkins自动化持续集成
    一、持续集成优势1.1解放重复劳动一次设置,多次复用。持续集成任务可以解放集成、测试、部署等重复性劳动,通过自动化任务能够显著提升集成频率。1.2更快解决问题接入持续集成任务后,能够更早地感知变更后效果,及时进入测试环节,更快暴露问题,降低解决问题的成本。1.3更快......
  • 快速入门:如何安装 IntelliJ IDEA 集成开发环境
    本文将指导您完成IntelliJIDEA的下载和安装过程,帮助您开始使用这个功能强大的Java集成开发环境。无论是新手还是经验丰富的开发者,IntelliJIDEA都能提供高效、智能的编程体验。对于Java开发者来说,一个合适的集成开发环境(IDE)是提高工作效率的利器。IntelliJIDEA,作为业界......
  • 【github】使用KeepassXC 解决github Enable two-factor authentication (2FA) 第二因
    下载https://github.com/keepassxreboot/keepassxc/releases/download/2.7.9/KeePassXC-2.7.9-Win64.msi代理地址https://dgithub.xyz/keepassxreboot/keepassxc/releases/download/2.7.9/KeePassXC-2.7.9-Win64.msi由于该软件不允许截图,以下操作参考官网创建数据库 Kee......
  • SLS 数据加工全面升级,集成 SPL 语法
    作者:灵圣数据加工概述在系统开发、运维过程中,日志是最重要的信息之一,其最大的优点是简单直接。不过在整个日志的生命周期里有一对很难调和的矛盾:输出和采集日志要求尽可能的简单便捷vs日志分析时需要数据格式化并能够按需存储。为了解决前者,保证服务的稳定和效率,提出了不同......
  • Jenkins持续集成软件
    1.什么是jenkins?   jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,提供一个开放易用的软件平台,时软件项目可以进行持续集成。通俗来说:Jenkins软件就是自动拉取git远程仓库所提交的项目,不用自己动手拉取等一些操作。2.为什么使......
  • Jenkins+Gitlab持续集成综合实战
    一、持续集成应用背景:DevOps:(英文Development(开发)和Operations(技术运营)的组合)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。它的出现是由于软件行业日益清晰地认识到:为了按时交付软件产品和服务,开发和运营工......
  • ToDesk的诈骗事件别害怕!荣获多个机构安全认证
    临近年关,诈骗事件层出不求,小社长注意到远控软件ToDesk最近又被骗子利用来盗取用户信息。原理就是通过话术让受害者交出远程控制软件的密码,通过电话一步步指使受害者操作设备,达到骗子的目的。从近期的诈骗事件来看,根据小社长的了解的过程细节,ToDesk属实无辜,好端端的被骗子拿来当......