博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Security整合KeyCloak保护Rest API
阅读量:6376 次
发布时间:2019-06-23

本文共 17583 字,大约阅读时间需要 58 分钟。

今天我们尝试Spring Security整合Keycloak,并决定建立一个非常简单的Spring Boot微服务,使用Keycloak作为我的身份验证源,使用Spring Security处理身份验证和授权。

设置Keycloak


  • 首先我们需要一个Keycloak实例,让我们启动Jboss提供的Docker容器:
docker run -d \  --name springboot-security-keycloak-integration \  -e KEYCLOAK_USER=admin \  -e KEYCLOAK_PASSWORD=admin \  -p 9001:8080 \  jboss/keycloak
  • 在此之后,我们只需登录到容器并导航到bin文件夹。
docker exec -it springboot-security-keycloak-integration /bin/bashcd keycloak/bin
  • 首先,我们需要从CLI客户端登录keycloak服务器,之后我们不再需要身份验证:
./kcadm.sh config credentials --server http://localhost:8080/auth --realm master --user admin --password admin

配置realm


  • 首先,我们需要创建一个realm:
./kcadm.sh create realms -s realm=springboot-security-keycloak-integration -s enabled=trueCreated new realm with id 'springboot-security-keycloak-integration'
  • 之后,我们需要创建2个客户端,这将为我们的应用程序提供身份验证。首先我们创建一个cURL客户端,这样我们就可以通过命令行命令登录:
./kcadm.sh create clients -r springboot-security-keycloak-integration -s clientId=curl -s enabled=true -s publicClient=true -s baseUrl=http://localhost:8080 -s adminUrl=http://localhost:8080 -s directAccessGrantsEnabled=trueCreated new client with id '8f0481cd-3bbb-4659-850f-6088466a4d89'

重要的是要注意2个选项:publicClient=truedirectAccessGrantsEnabled=true。第一个使这个客户端公开,这意味着我们的cURL客户端可以在不提供任何秘密的情况下启动登录。第二个使我们能够使用用户名和密码直接登录。

  • 其次,我们创建了一个由REST服务使用的客户端:
./kcadm.sh create clients -r springboot-security-keycloak-integration -s clientId=springboot-security-keycloak-integration-client -s enabled=true -s baseUrl=http://localhost:8080 -s bearerOnly=trueCreated new client with id 'ab9d404e-6d5b-40ac-9bc3-9e2e26b68213'

这里的重要配置是bearerOnly=true。这告诉Keycloak客户端永远不会启动登录过程,但是当它收到Bearer令牌时,它将检查所述令牌的有效性。

我们应该注意保留这些ID,因为我们将在接下来的步骤中使用它们。
  • 我们有两个客户端,接下来是为spring-security-keycloak-example-app客户创建角色

Admin Role:

./kcadm.sh create clients/ab9d404e-6d5b-40ac-9bc3-9e2e26b68213/roles -r springboot-security-keycloak-integration -s name=admin -s 'description=Admin role'Created new role with id 'admin'

User Role:

./kcadm.sh create clients/ab9d404e-6d5b-40ac-9bc3-9e2e26b68213/roles -r springboot-security-keycloak-integration -s name=user -s 'description=User role'Created new role with id 'user'
注意client后的id是我们创建客户端输出的id
  • 最后,我们应该获取客户端的配置,以便稍后提供给我们的应用程序:
./kcadm.sh  get clients/ab9d404e-6d5b-40ac-9bc3-9e2e26b68213/installation/providers/keycloak-oidc-keycloak-json -r springboot-security-keycloak-integration
注意client后的id是我们创建客户端输出的id

应该返回类似于此的内容:

{  "realm" : "springboot-security-keycloak-integration",  "bearer-only" : true,  "auth-server-url" : "http://localhost:8080/auth",  "ssl-required" : "external",  "resource" : "springboot-security-keycloak-integration-client",  "verify-token-audience" : true,  "use-resource-role-mappings" : true,  "confidential-port" : 0}

配置用户


出于演示目的,我们创建2个具有2个不同角色的用户,以便我们验证授权是否有效。

  • 首先,让我们创建一个具有admin角色的用户:

创建admin用户:

./kcadm.sh create users -r springboot-security-keycloak-integration -s username=admin -s enabled=trueCreated new user with id '50c11a76-a8ff-42b1-80cb-d82cb3e7616d'

设置admin密码:

./kcadm.sh update users/50c11a76-a8ff-42b1-80cb-d82cb3e7616d/reset-password -r springboot-security-keycloak-integration -s type=password -s value=admin -s temporary=false -n

value: 用户密码

追加到admin角色中

./kcadm.sh add-roles -r springboot-security-keycloak-integration --uusername=admin --cclientid springboot-security-keycloak-integration-client --rolename admin
注意:从不在生产中使用此方法,它仅用于演示目的!
  • 然后我们创建另一个用户,这次有角色user:

创建user用户:

./kcadm.sh create users -r springboot-security-keycloak-integration -s username=user -s enabled=trueCreated new user with id '624434c8-bce4-4b5b-b81f-e77304785803'

设置user密码:

./kcadm.sh update users/624434c8-bce4-4b5b-b81f-e77304785803/reset-password -r springboot-security-keycloak-integration -s type=password -s value=admin -s temporary=false -n

追加到user角色中:

./kcadm.sh add-roles -r springboot-security-keycloak-integration --uusername=user --cclientid springboot-security-keycloak-integration-client --rolename user

Rest服务


我们已经配置了Keycloak并准备使用,我们只需要一个应用程序来使用它!所以我们创建一个简单的Spring Boot应用程序。我会在这里使用maven构建项目:

4.0.0
com.edurt.sski
springboot-security-keycloak-integration
jar
1.0.0
springboot security keycloak integration
SpringBoot Security KeyCloak Integration is a open source springboot, spring security, keycloak integration example.
1.16.16
1.5.6.RELEASE
3.1.0.Final
3.3
2.10.4
1.8
2.5
org.springframework.boot
spring-boot-dependencies
${dependency.springboot.common.version}
pom
import
org.projectlombok
lombok
${dependency.lombox.version}
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-security
org.keycloak
keycloak-spring-boot-starter
${dependency.keycloak.version}
org.keycloak
keycloak-spring-security-adapter
${dependency.keycloak.version}
org.apache.maven.plugins
maven-compiler-plugin
${plugin.maven.compiler.version}
${environment.compile.java.version}
${environment.compile.java.version}
org.apache.maven.plugins
maven-javadoc-plugin
${plugin.maven.javadoc.version}
true
Description
test
description
-Xdoclint:none
org.apache.maven.plugins
maven-jxr-plugin
${reporting.maven.jxr.version}

添加所有必需的依赖项:

  • spring-security 用于保护应用程序
  • keycloak-spring-boot-starter 使用Keycloak和Spring Boot
  • keycloak-spring-security-adapter 与Spring Security集成

一个简单的应用类:

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements.  See the NOTICE file * distributed with this work for additional information * regarding copyright ownership.  The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License.  You may obtain a copy of the License at * 

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.edurt.sski;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;/** *

SpringBootSecurityKeyCloakIntegration

*

Description : SpringBootSecurityKeyCloakIntegration

*

Author : qianmoQ

*

Version : 1.0

*

Create Time : 2019-02-18 14:45

*

Author Email: qianmoQ

*/@SpringBootApplicationpublic class SpringBootSecurityKeyCloakIntegration { public static void main(String[] args) { SpringApplication.run(SpringBootSecurityKeyCloakIntegration.class, args); }}

Rest API接口:

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements.  See the NOTICE file * distributed with this work for additional information * regarding copyright ownership.  The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License.  You may obtain a copy of the License at * 

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.edurt.sski.controller;import org.springframework.security.access.annotation.Secured;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;/** *

HelloController

*

Description : HelloController

*

Author : qianmoQ

*

Version : 1.0

*

Create Time : 2019-02-18 14:50

*

Author Email: qianmoQ

*/@RestControllerpublic class HelloController { @GetMapping(value = "/admin") @Secured("ROLE_ADMIN") public String admin() { return "Admin"; } @GetMapping("/user") @Secured("ROLE_USER") public String user() { return "User"; }}

最后是keycloak配置:

/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements.  See the NOTICE file * distributed with this work for additional information * regarding copyright ownership.  The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License.  You may obtain a copy of the License at * 

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.edurt.sski.config;import org.keycloak.adapters.KeycloakConfigResolver;import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter;import org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;/** *

KeycloakSecurityConfigurer

*

Description : KeycloakSecurityConfigurer

*

Author : qianmoQ

*

Version : 1.0

*

Create Time : 2019-02-18 14:51

*

Author Email: qianmoQ

*/@Configuration@EnableWebSecuritypublic class KeycloakSecurityConfigurer extends KeycloakWebSecurityConfigurerAdapter { @Bean public GrantedAuthoritiesMapper grantedAuthoritiesMapper() { SimpleAuthorityMapper mapper = new SimpleAuthorityMapper(); mapper.setConvertToUpperCase(true); return mapper; } @Override protected KeycloakAuthenticationProvider keycloakAuthenticationProvider() { final KeycloakAuthenticationProvider provider = super.keycloakAuthenticationProvider(); provider.setGrantedAuthoritiesMapper(grantedAuthoritiesMapper()); return provider; } @Override protected void configure(final AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(keycloakAuthenticationProvider()); } @Override protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { return new NullAuthenticatedSessionStrategy(); } @Override protected void configure(final HttpSecurity http) throws Exception { super.configure(http); http .authorizeRequests() .antMatchers("/admin").hasRole("ADMIN") .antMatchers("/user").hasRole("USER") .anyRequest().permitAll(); } @Bean KeycloakConfigResolver keycloakConfigResolver() { return new KeycloakSpringBootConfigResolver(); } @Bean public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean( final KeycloakAuthenticationProcessingFilter filter) { final FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter); registrationBean.setEnabled(false); return registrationBean; } @Bean public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean( final KeycloakPreAuthActionsFilter filter) { final FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter); registrationBean.setEnabled(false); return registrationBean; }}

KeycloakSecurityConfigurer类扩展 KeycloakWebSecurityConfigurerAdapter,这是Keycloak提供的类,它提供与Spring Security的集成。

然后我们通过添加配置身份验证管理器,它负责转换来自Keycloak的角色名称以匹配Spring Security的约定。基本上Spring Security期望以ROLE_前缀开头的角色,ROLE_ADMIN可以像Keycloak一样命名我们的角色,或者我们可以将它们命名为admin,然后使用此映射器将其转换为大写并添加必要的ROLE_前缀:

@Beanpublic GrantedAuthoritiesMapper grantedAuthoritiesMapper() {  SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();  mapper.setConvertToUpperCase(true);  return mapper;}@Overrideprotected KeycloakAuthenticationProvider keycloakAuthenticationProvider() {  final KeycloakAuthenticationProvider provider = super.keycloakAuthenticationProvider();  provider.setGrantedAuthoritiesMapper(grantedAuthoritiesMapper());  return provider;}@Overrideprotected void configure(final AuthenticationManagerBuilder auth) throws Exception {  auth.authenticationProvider(keycloakAuthenticationProvider());}

我们还需要为Keycloak设置会话策略,但是当我们创建无状态REST服务时,我们并不真的想要有会话,因此我们使用NullAuthenticatedSessionStrategy:

@Overrideprotected SessionAuthenticationStrategy sessionAuthenticationStrategy() {  return new NullAuthenticatedSessionStrategy();}

通常,Keycloak Spring Security集成从keycloak.json文件中解析keycloak配置,但是我们希望有适当的Spring Boot配置,因此我们使用Spring Boot覆盖配置解析器:

@BeanKeycloakConfigResolver keycloakConfigResolver() {  return new KeycloakSpringBootConfigResolver();}

然后我们配置Spring Security来授权所有请求:

@Overrideprotected void configure(final HttpSecurity http) throws Exception {  super.configure(http);  http      .authorizeRequests()      .anyRequest().permitAll();}

最后,根据文档,我们阻止双重注册Keycloak的过滤器:

@Beanpublic FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(    final KeycloakAuthenticationProcessingFilter filter) {  final FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);  registrationBean.setEnabled(false);  return registrationBean;}@Beanpublic FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(    final KeycloakPreAuthActionsFilter filter) {  final FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);  registrationBean.setEnabled(false);  return registrationBean;}

最后,我们需要application.properties使用之前下载的值配置我们的应用程序 :

server.port=9002keycloak.realm=springboot-security-keycloak-integrationkeycloak.bearer-only=truekeycloak.auth-server-url=http://localhost:9001/authkeycloak.ssl-required=externalkeycloak.resource=springboot-security-keycloak-integration-clientkeycloak.use-resource-role-mappings=truekeycloak.principal-attribute=preferred_username

使用应用程序


  • 使用curl我们创建的客户端进行身份验证,以获取访问令牌:
export TOKEN=`curl -ss --data "grant_type=password&client_id=curl&username=admin&password=admin" http://localhost:9001/auth/realms/springboot-security-keycloak-integration/protocol/openid-connect/token | jq -r .access_token`

这将收到的访问令牌存储在TOKEN变量中。

现在我们可以检查我们的管理员是否可以访问自己的/admin接口

curl -H "Authorization: bearer $TOKEN" http://localhost:9002/adminAdmin

但它无法访问/user接口:

$ curl -H "Authorization: bearer $TOKEN" http://localhost:9002/user{"timestamp":1498728302626,"status":403,"error":"Forbidden","message":"Access is denied","path":"/user"}

对于user用户也是如此,user用户无法访问admin接口。

源码地址:

转载地址:http://vuxqa.baihongyu.com/

你可能感兴趣的文章
为什么实体类要实现序列化
查看>>
JVM的重排序
查看>>
某个时间为星期几
查看>>
01背包解题模板
查看>>
antd table 点击行触发radio 或 checkbox
查看>>
利用Adaboost提高分类性能
查看>>
tensorflow之损失函数
查看>>
CENTOS6.2系统日志rsyslog替换默认的日志服务syslog 转载自http://www.phpboy.net/linux/648.html...
查看>>
css3 炫酷下拉菜单
查看>>
前端存取cookie
查看>>
linux c笔记
查看>>
第四次作业
查看>>
angular 5的新特性
查看>>
tcp中设置连接超时
查看>>
java基础.1——String类
查看>>
html,css,javascript三者之间的相互关系是什么
查看>>
Educational Codeforces Round 48 (Rated for Div. 2) B 1016B Segment Occurrences (前缀和)
查看>>
SQL SERVER 2005 附加 SQL SERVER 2000数据库的办法
查看>>
echart折线图系列一:折线图基本配置
查看>>
leetcode 278. First Bad Version
查看>>