登陸及身份認證是現代web應用最基本的功能之一,對於企業內部的系統,多個系統每每但願有一套SSO服務對企業用戶的登陸及身份認證進行統一的管理,提高用戶同時使用多個系統的體驗,Keycloak正是爲此種場景而生。本文將簡明的介紹Keycloak的安裝、使用,並給出目前較流行的先後端分離應用如何快速接入Keycloak的示例。前端
Keycloak是一種面向現代應用和服務的開源IAM(身份識別與訪問管理)解決方案vue
Keycloak提供了單點登陸(SSO)功能,支持OpenID Connect
、OAuth 2.0
、SAML 2.0
標準協議,擁有簡單易用的管理控制檯,並提供對LDAP、Active Directory以及Github、Google等社交帳號登陸的支持,作到了很是簡單的開箱即用。react
首先經過官方的一張圖來了解下總體的核心概念ios
這裏先只介紹4個最經常使用的核心概念:web
Users
: 用戶,使用並須要登陸系統的對象spring
Roles
: 角色,用來對用戶的權限進行管理docker
Clients
: 客戶端,須要接入Keycloak並被Keycloak保護的應用和服務npm
Realms
: 領域,領域管理着一批用戶、證書、角色、組等,一個用戶只能屬於而且能登錄到一個域,域之間是互相獨立隔離的, 一個域只能管理它下面所屬的用戶Keycloak安裝有多種方式,這裏使用Docker進行快速安裝axios
docker run -d --name keycloak \ -p 8080:8080 \ -e KEYCLOAK_USER=admin \ -e KEYCLOAK_PASSWORD=admin \ jboss/keycloak:10.0.0
訪問http://localhost:8080並點擊Administration Console進行登陸後端
建立一個新的realm: demo,後續全部的客戶端、用戶、角色等都在此realm中建立
建立一個新的客戶端:vue-demo,Access Type選擇public
建立一個新的客戶端:spring-boot-demo,Access Type選擇bearer-only
保存以後,會出現Credentials的Tab,記錄下這裏的secret,後面要用到
上面建立的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
vue create vue-demo
npm i keycloak-js --save npm i axios --save
import Vue from 'vue' import App from './App.vue' import Keycloak from 'keycloak-js' Vue.config.productionTip = false // keycloak init options const initOptions = { url: 'http://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) })
<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: 'http://127.0.0.1:8082/admin', headers: {'Authorization': 'Bearer ' + this.$keycloak.token} }) }, getCustomer() { return axios({ method: 'get', url: 'http://127.0.0.1:8082/customer', headers: {'Authorization': 'Bearer ' + this.$keycloak.token} }) } } } </script>
getAdmin()
及getCustomer()
這2個方法內部分別請求restful api
<dependency> <groupId>org.keycloak</groupId> <artifactId>keycloak-spring-boot-starter</artifactId> <version>10.0.0</version> </dependency>
官方文檔及網上大部分示例使用的都是properties格式的配置文件,而yaml格式的配置文件相對更簡潔清晰些,此示例使用yaml格式的配置文件,內容以下
server: port: 8082 keycloak: realm: demo auth-server-url: http://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
角色的用戶才能訪問@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項目會跳轉Keycloak登陸頁
Keycloak部署及接入簡單,輕量的同時功能又不失強大,很是適合企業內部的SSO方案。