Keycloak快速上手指南,只需10分鐘即可接入Spring Boot/Vue前後端分離應用實現SSO單點登錄
- 2020 年 6 月 2 日
- 筆記
- JAVA, keycloak, Spring Boot
登錄及身份認證是現代web應用最基本的功能之一,對於企業內部的系統,多個系統往往希望有一套SSO服務對企業用戶的登錄及身份認證進行統一的管理,提升用戶同時使用多個系統的體驗,Keycloak正是為此種場景而生。本文將簡明的介紹Keycloak的安裝、使用,並給出目前較流行的前後端分離應用如何快速接入Keycloak的示例。
Keycloak是什麼
Keycloak是一種面向現代應用和服務的開源IAM(身份識別與訪問管理)解決方案
Keycloak提供了單點登錄(SSO)功能,支援OpenID Connect
、OAuth 2.0
、SAML 2.0
標準協議,擁有簡單易用的管理控制台,並提供對LDAP、Active Directory以及Github、Google等社交帳號登錄的支援,做到了非常簡單的開箱即用。
Keycloak常用核心概念介紹
首先通過官方的一張圖來了解下整體的核心概念
這裡先只介紹4個最常用的核心概念:
-
Users
: 用戶,使用並需要登錄系統的對象 -
Roles
: 角色,用來對用戶的許可權進行管理 -
Clients
: 客戶端,需要接入Keycloak並被Keycloak保護的應用和服務 -
Realms
: 領域,領域管理著一批用戶、證書、角色、組等,一個用戶只能屬於並且能登陸到一個域,域之間是互相獨立隔離的, 一個域只能管理它下面所屬的用戶
Keycloak服務安裝及配置
安裝Keycloak
Keycloak安裝有多種方式,這裡使用Docker進行快速安裝
docker run -d --name keycloak \
-p 8080:8080 \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=admin \
jboss/keycloak:10.0.0
訪問//localhost:8080並點擊Administration Console進行登錄
創建Realm
創建一個新的realm: demo,後續所有的客戶端、用戶、角色等都在此realm中創建
創建客戶端
創建前端應用客戶端
創建一個新的客戶端:vue-demo,Access Type選擇public
創建後端應用客戶端
創建一個新的客戶端:spring-boot-demo,Access Type選擇bearer-only
保存之後,會出現Credentials的Tab,記錄下這裡的secret,後面要用到
關於客戶端的訪問類型(Access Type)
上面創建的2個客戶端的訪問類型分別是public、bearer-only,那麼為什麼分別選擇這種類型,實際不同的訪問類型有什麼區別呢?
事實上,Keycloak目前的訪問類型共有3種:
confidential
:適用於服務端應用,且需要瀏覽器登錄以及需要通過密鑰獲取access token
的場景。典型的使用場景就是服務端渲染的web系統。
public
:適用於客戶端應用,且需要瀏覽器登錄的場景。典型的使用場景就是前端web系統,包括採用vue、react實現的前端項目等。
bearer-only
:適用於服務端應用,不需要瀏覽器登錄,只允許使用bearer token
請求的場景。典型的使用場景就是restful api。
創建用戶和角色
創建角色
創建2個角色:ROLE_ADMIN、ROLE_CUSTOMER
創建用戶
創建2個用戶:admin、customer
綁定用戶和角色
給admin用戶分配角色ROLE_ADMIN
給customer用戶分配角色ROLE_CUSTOMER
Vue應用集成Keycloak簡明指南
創建vue項目
vue create vue-demo
添加官方Keycloak js適配器
npm i keycloak-js --save
npm i axios --save
main.js
import Vue from 'vue'
import App from './App.vue'
import Keycloak from 'keycloak-js'
Vue.config.productionTip = false
// keycloak init options
const initOptions = {
url: '//127.0.0.1:8080/auth',
realm: 'demo',
clientId: 'vue-demo',
onLoad:'login-required'
}
const keycloak = Keycloak(initOptions)
keycloak.init({ onLoad: initOptions.onLoad, promiseType: 'native' }).then((authenticated) =>{
if(!authenticated) {
window.location.reload();
} else {
Vue.prototype.$keycloak = keycloak
console.log('Authenticated')
}
new Vue({
render: h => h(App),
}).$mount('#app')
setInterval(() =>{
keycloak.updateToken(70).then((refreshed)=>{
if (refreshed) {
console.log('Token refreshed');
} else {
console.log('Token not refreshed, valid for '
+ Math.round(keycloak.tokenParsed.exp + keycloak.timeSkew - new Date().getTime() / 1000) + ' seconds');
}
}).catch(error => {
console.log('Failed to refresh token', error)
})
}, 60000)
}).catch(error => {
console.log('Authenticated Failed', error)
})
HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<div>
<p>
current user: {{user}}
</p>
<p>
roles: {{roles}}
</p>
<p>
{{adminMsg}}
</p>
<p>
{{customerMsg}}
</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
user: '',
roles: [],
adminMsg: '',
customerMsg: ''
}
},
created() {
this.user = this.$keycloak.idTokenParsed.preferred_username
this.roles = this.$keycloak.realmAccess.roles
this.getAdmin()
.then(response=>{
this.adminMsg = response.data
})
.catch(error => {
console.log(error)
})
this.getCustomer()
.then(response => {
this.customerMsg = response.data
})
.catch(error => {
console.log(error)
})
},
methods: {
getAdmin() {
return axios({
method: 'get',
url: '//127.0.0.1:8082/admin',
headers: {'Authorization': 'Bearer ' + this.$keycloak.token}
})
},
getCustomer() {
return axios({
method: 'get',
url: '//127.0.0.1:8082/customer',
headers: {'Authorization': 'Bearer ' + this.$keycloak.token}
})
}
}
}
</script>
getAdmin()
及getCustomer()
這2個方法內部分別請求restful api
Spring Boot應用集成Keycloak簡明指南
添加Keycloak Maven依賴
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>10.0.0</version>
</dependency>
Spring Boot配置文件
官方文檔及網上大部分示例使用的都是properties格式的配置文件,而yaml格式的配置文件相對更簡潔清晰些,此示例使用yaml格式的配置文件,內容如下
server:
port: 8082
keycloak:
realm: demo
auth-server-url: //127.0.0.1:8080/auth
resource: spring-boot-demo
ssl-required: external
credentials:
secret: 2d2ab498-7af9-48c0-89a3-5eec929e462b
bearer-only: true
use-resource-role-mappings: false
cors: true
security-constraints:
- authRoles:
- ROLE_CUSTOMER
securityCollections:
- name: customer
patterns:
- /customer
- authRoles:
- ROLE_ADMIN
securityCollections:
- name: admin
patterns:
- /admin
除了幾個必填的配置項外,另外需要注意的幾個配置項如下
credentials.secret
:上文添加客戶端後Credentials Tab內對應的內容
bearer-only
:設置為true,表示此應用的Keycloak訪問類型是bearer-only
cors
:設置為true表示允許跨域訪問
security-constraints
:主要是針對不同的路徑定義角色以達到許可權管理的目的
/customer
:只允許擁有ROLE_CUSTOMER
角色的用戶才能訪問/admin
:只允許擁有ROLE_ADMIN
角色的用戶才能訪問- 未配置的路徑表示公開訪問
Controller內容
@RestController
public class HomeController {
@RequestMapping("/")
public String index() {
return "index";
}
@RequestMapping("/customer")
public String customer() {
return "only customer can see";
}
@RequestMapping("/admin")
public String admin() {
return "only admin cas see";
}
}
項目效果演示
分別啟動前後端項目後,本地8081埠對應vue前端項目,本地8082埠對應Spring Boot實現的restful api項目
首次訪問vue前端項目
第一次訪問vue項目會跳轉Keycloak登錄頁
登錄admin用戶
登錄customer用戶
總結
Keycloak部署及接入簡單,輕量的同時功能又不失強大,非常適合企業內部的SSO方案。
本文示例項目地址:keycloak-demo