keycloak-鉴权springboot3后端服务

2024-05-24 08:04

本文主要是介绍keycloak-鉴权springboot3后端服务,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、问题描述

springboot一般都用于后端服务,所以keycloak只需要验证JWT是否满足鉴权即可,此方式在keycloak中客户端配置bear-only方式。然而springboot3不再直接集成keycloak,yml中直接配置keycloak不起作用。那么,springboot3如何集成keycloak鉴权jwt呢?

二、解决方案

2.1 环境描述

springboot:3.0.1

keycloak: 18.0.1

2.2 解决方案

1、pom.xml 引入jar包

集成5个包,包括keycloak两个,security一个,oauth2两个(jwt方式集成keycloak)

        <!-- 集成keycloak所需要的包 - 开始 --><!-- 管理员客户端API   注册和创建client、realm需要用到的 --><dependency><groupId>org.keycloak</groupId><artifactId>keycloak-admin-client</artifactId><version>18.0.1</version></dependency><dependency><groupId>org.keycloak</groupId><artifactId>keycloak-spring-boot-starter</artifactId><version>18.0.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-resource-server</artifactId></dependency><!-- 集成keycloak所需要的包 - 结束 -->

2、application.yml配置

将keycloak鉴权集成到jwt中,springboot已集成了jwt

spring:#keycloak 鉴权相关配置security:oauth2:resourceserver:jwt:# user-login 是我的一个域(realms)issuer-uri: https://127.0.0.1:8443/realms/user_loginjwk-set-uri: https://127.0.0.1:8443//realms/user_login/protocol/openid-connect/certs

至此,已经可以keycloak鉴权了,如果来自前端的请求没有带正确Authorization会被拦截返回401,但是,如何放行部分链接呢?请看第三步

3、注入 securityFilterChain Bean,直接粘贴代码吧

package com.hlxx.finance.config;import com.hlxx.finance.controller.FinanceController;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtDecoders;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.context.SecurityContextPersistenceFilter;import java.io.IOException;/*** Keycloak对应的Security文件* 解决方案来自于 GPT4.0 + 智谱清言*/
@Configuration
@EnableWebSecurity
public class SecurityConfigKeyCloak {private static Logger logger = LoggerFactory.getLogger(SecurityConfigKeyCloak.class);@Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {http.addFilterBefore(new LoggingFilter(), SecurityContextPersistenceFilter.class) // 添加拦截器在Spring Security过滤器链之前// 其他安全配置....csrf(csrf -> csrf.ignoringRequestMatchers("/public/**") // 为特定URL禁用CSRF保护).authorizeHttpRequests(authorizeRequests -> authorizeRequests.requestMatchers("/public/**").permitAll() // 放行公开的链接.anyRequest().authenticated()).oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt
//                            .decoder(jwtDecoder()).jwtAuthenticationConverter(jwtAuthenticationConverter())))// 使用新的配置器替代 exceptionHandling().exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(new CustomBearerTokenAuthenticationEntryPoint()).accessDeniedHandler(new CustomAccessDeniedHandler()));return http.build();}//    @Bean
//    public JwtDecoder jwtDecoder() {
//        // 配置 JWT 解码器
//        return JwtDecoders.fromIssuerLocation("http://127.0.0.1:8080/realms/user_login");
//    }// 自定义访问被拒绝处理器private JwtAuthenticationConverter jwtAuthenticationConverter() {System.out.println("被拒绝处理器");JwtAuthenticationConverter converter = new JwtAuthenticationConverter();converter.setJwtGrantedAuthoritiesConverter(new JwtGrantedAuthoritiesConverter());return converter;}// 自定义访问被拒绝处理器private static class CustomBearerTokenAuthenticationEntryPoint implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException {response.setStatus(HttpStatus.UNAUTHORIZED.value());response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.getWriter().write("{\"code\": 401, \"error\": \"Unauthorized\", \"message\": \"JWT token is invalid or expired\"}");}}// 自定义访问被拒绝处理器private static class CustomAccessDeniedHandler implements AccessDeniedHandler {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, org.springframework.security.access.AccessDeniedException accessDeniedException) throws IOException, ServletException {response.setStatus(HttpStatus.FORBIDDEN.value());response.setContentType(MediaType.APPLICATION_JSON_VALUE);response.getWriter().write("{\"code\": 401, \"error\": \"Forbidden\", \"message\": \"Access denied due to invalid credentials\"}");}}
}

代码中的LoggerFactory是另一个类,用于记录日志调试,代码如下

package com.hlxx.finance.config;import com.alibaba.fastjson2.JSONObject;
import com.nimbusds.jose.shaded.gson.JsonObject;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;import java.io.IOException;@Component
public class LoggingFilter extends OncePerRequestFilter {private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {try {logger.info("Request URL: {}", request.getRequestURL());// 其他需要记录的信息filterChain.doFilter(request, response);} catch (Exception e) {// 异常处理logger.error("Exception occurred: {}", e.getMessage(), e);throw e;}}
}

至此,问题解决

三、仍然存在的问题

1、放行的链接,如果前端不带Authorization会直接放行,但是带了错误的Authorization还是会拦截。

2、错误的Authorization会返回response为空。

以上两个问题尝试未果,然后通过调整前端去解决了,有遇到的请留言解决方案,感谢。

这篇关于keycloak-鉴权springboot3后端服务的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/997836

相关文章

springboot3.x使用@NacosValue无法获取配置信息的解决过程

《springboot3.x使用@NacosValue无法获取配置信息的解决过程》在SpringBoot3.x中升级Nacos依赖后,使用@NacosValue无法动态获取配置,通过引入SpringC... 目录一、python问题描述二、解决方案总结一、问题描述springboot从2android.x

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?

Springboot3 ResponseEntity 完全使用案例

《Springboot3ResponseEntity完全使用案例》ResponseEntity是SpringBoot中控制HTTP响应的核心工具——它能让你精准定义响应状态码、响应头、响应体,相比... 目录Spring Boot 3 ResponseEntity 完全使用教程前置准备1. 项目基础依赖(M

nacos服务无法注册到nacos服务中心问题及解决

《nacos服务无法注册到nacos服务中心问题及解决》本文详细描述了在Linux服务器上使用Tomcat启动Java程序时,服务无法注册到Nacos的排查过程,通过一系列排查步骤,发现问题出在Tom... 目录简介依赖异常情况排查断点调试原因解决NacosRegisterOnWar结果总结简介1、程序在

requests处理token鉴权接口和jsonpath使用方式

《requests处理token鉴权接口和jsonpath使用方式》文章介绍了如何使用requests库进行token鉴权接口的处理,包括登录提取token并保存,还详述了如何使用jsonpath表达... 目录requests处理token鉴权接口和jsonpath使用json数据提取工具总结reques

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他

Java服务实现开启Debug远程调试

《Java服务实现开启Debug远程调试》文章介绍如何通过JVM参数开启Java服务远程调试,便于在线上排查问题,在IDEA中配置客户端连接,实现无需频繁部署的调试,提升效率... 目录一、背景二、相关图示说明三、具体操作步骤1、服务端配置2、客户端配置总结一、背景日常项目中,通常我们的代码都是部署到远程

Java MCP 的鉴权深度解析

《JavaMCP的鉴权深度解析》文章介绍JavaMCP鉴权的实现方式,指出客户端可通过queryString、header或env传递鉴权信息,服务器端支持工具单独鉴权、过滤器集中鉴权及启动时鉴权... 目录一、MCP Client 侧(负责传递,比较简单)(1)常见的 mcpServers json 配置

sysmain服务可以禁用吗? 电脑sysmain服务关闭后的影响与操作指南

《sysmain服务可以禁用吗?电脑sysmain服务关闭后的影响与操作指南》在Windows系统中,SysMain服务(原名Superfetch)作为一个旨在提升系统性能的关键组件,一直备受用户关... 在使用 Windows 系统时,有时候真有点像在「开盲盒」。全新安装系统后的「默认设置」,往往并不尽编