13-SpringSecurity:OpenID与Keycloak

本文详细介绍了如何在SpringSecurity中集成KeycloakOAuth2,包括配置application.yml,创建Controller以展示登录流程,查看Keycloak注册信息和AccessToken,以及使用JWT和OAuth2访问KeycloakAPI获取用户信息。作者还分享了Java工程师的学习资源推荐。
摘要由CSDN通过智能技术生成

(2) 配置 application.yml

spring:

security:

oauth2:

client:

provider:

keycloak:

issuer-uri: http://localhost:8080/auth/realms/heartsuit

registration:

keycloak:

client-id: springsecurity

client-secret: 6b532289-4c11-4e62-acc0-5c67e13e4736

clientName: Keycloak

scope:

  • openid

  • profile

  • email

server:

port: 8000

(3) 启动应用

为了看到登录成功后的效果,这里增加一个 Controller ;然后运行应用。

@GetMapping(value = “/”)

public String index(Principal principal) {

return "Welcome " + principal;

}

在浏览器键入: http://localhost:8000/login ,返回一个页面,其中包含了 Keycloak 登录链接:

2021-01-27-Login.png

点击 Keycloak 登录链接,会自动跳转至 我们创建的 Keycloak 服务认证页:

2021-01-27-LoginForm.png

输入在 Heartsuit 域下创建的用户: auth ,会进入我们之前配置的Home页,显示用户信息。

Note: 如果我们直接在浏览器中输入 http://localhost:8000 则会自动跳转到

http://localhost:8080/auth/realms/heartsuit/protocol/openid-connect/auth?response_type=code&client_id=springsecurity&state=Gd5Xj0PyueFcDtoQ6zC6w2wSVc4XjAbAFn8q_uu0qes%3D&redirect_uri=http://localhost:8000/login/oauth2/code/keycloak 链接。

可通过链接退出: http://localhost:8000/logout

借助 SpringSecurityOpenID 的支持,我们几乎不用写什么代码就实现了 Keycloak 登录集成。下面简单了解下登录成功后的 RegistrationAccessToken

实验2:查看Keycloak在我们应用中的注册信息

为了方便调试或查看 registration ,这里新增一个接口端点:

@GetMapping(value = “/user/reg”)

public String registration() {

ClientRegistration keycloakRegistration = this.clientRegistrationRepository.findByRegistrationId(“keycloak”);

log.info(keycloakRegistration.toString());

return keycloakRegistration.toString();

}

访问之后会返回 registration 信息,其中包含了 clientIdclientSecretauthorizationGrantTyperedirectUriscopes 等。

2021-01-27-KeycloakRegistration.png

实验3:查看获取到的AccessToken

@GetMapping(value = “/user/token”)

public OAuth2AccessToken accessToken(OAuth2AuthenticationToken authentication) {

OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient(

authentication.getAuthorizedClientRegistrationId(), authentication.getName());

OAuth2AccessToken accessToken = authorizedClient.getAccessToken();

return accessToken;

}

在这里插入图片描述

显然,这里的 tokenValue 是一个 JWT 字符串,我们到 https://jwt.io 解析一下:

在这里插入图片描述

实验4:通过AccessToken请求Keycloak的用户信息接口

定义抽象 API 绑定类,通过拦截器将获取到的 AccessToken 设置到后续请求头中,通过 RestTemplate 实现对 API 的请求:

public abstract class ApiBinding {

protected RestTemplate restTemplate;

public ApiBinding(String accessToken) {

this.restTemplate = new RestTemplate();

if (accessToken != null) {

this.restTemplate.getInterceptors().add(getBearerTokenInterceptor(accessToken));

} else {

this.restTemplate.getInterceptors().add(getNoTokenInterceptor());

}

}

private ClientHttpRequestInterceptor getBearerTokenInterceptor(String accessToken) {

return new ClientHttpRequestInterceptor() {

@Override

public ClientHttpResponse intercept(HttpRequest request, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {

request.getHeaders().add(“Authorization”, "Bearer " + accessToken);

return execution.execute(request, bytes);

}

};

}

private ClientHttpRequestInterceptor getNoTokenInterceptor() {

return new ClientHttpRequestInterceptor() {

@Override

public ClientHttpResponse intercept(HttpRequest request, byte[] bytes, ClientHttpRequestExecution execution) throws IOException {

throw new IllegalStateException(“Can’t access the Keycloak API without an access token”);

}

};

}

}

将获取 AccessToken 的过程进行封装:

@Configuration

@Slf4j

public class SocialConfig {

@Bean

@RequestScope

public Keycloak keycloak(OAuth2AuthorizedClientService clientService) {

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

String accessToken = null;

String userInfoEndpointUri = null;

if (authentication.getClass().isAssignableFrom(OAuth2AuthenticationToken.class)) {

OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;

String clientRegistrationId = oauthToken.getAuthorizedClientRegistrationId();

if (clientRegistrationId.equals(“keycloak”)) {

OAuth2AuthorizedClient client = clientService.loadAuthorizedClient(clientRegistrationId, oauthToken.getName());

if (client != null) {

accessToken = client.getAccessToken().getTokenValue();

userInfoEndpointUri = client.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri();

}

log.info(accessToken);

log.info(userInfoEndpointUri);

}

}

return new Keycloak(accessToken, userInfoEndpointUri);

}

}

public class Keycloak extends ApiBinding {

private String userInfoEndpointUri;

public Keycloak(String accessToken, String userInfoEndpointUri) {

super(accessToken);

this.userInfoEndpointUri = userInfoEndpointUri;

}

public String getProfile() {

return restTemplate.getForObject(userInfoEndpointUri, String.class);

}

}

Controller 中新增接口:通过 AccessToken 获取 keycloak 用户信息:

@GetMapping(value = “/user/info”)

public String info() {

String profile = keycloak.getProfile();

log.info(keycloak.getProfile());

return profile;

}

2021-01-27-UserInfo.png

Controller 的完整代码:

@RestController

@Slf4j

public class HelloController {

@Autowired

private ClientRegistrationRepository clientRegistrationRepository;

@Autowired

private OAuth2AuthorizedClientService authorizedClientService;

@Autowired

Keycloak keycloak;

@GetMapping(value = “/”)

public String index(Principal principal) {

return "Welcome " + principal;

}

@GetMapping(value = “/user/reg”)

public String registration() {

ClientRegistration keycloakRegistration = this.clientRegistrationRepository.findByRegistrationId(“keycloak”);

log.info(keycloakRegistration.toString());

return keycloakRegistration.toString();

}

@GetMapping(value = “/user/token”)

public OAuth2AccessToken accessToken(OAuth2AuthenticationToken authentication) {

OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient(

authentication.getAuthorizedClientRegistrationId(), authentication.getName());

OAuth2AccessToken accessToken = authorizedClient.getAccessToken();

return accessToken;

}

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-TNfAnYQk-1714702601903)]

[外链图片转存中…(img-8UxJzUAj-1714702601904)]

[外链图片转存中…(img-gZ7bcwNb-1714702601904)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值