登陆及身份认证是现代web应用最基本的功能之一,对于企业内部的系统,多个系统每每但愿有一套SSO服务对企业用户的登陆及身份认证进行统一的管理,提高用户同时使用多个系统的体验,Keycloak正是为此种场景而生。本文将简明的介绍Keycloak的安装、使用,并给出目前较流行的先后端分离应用如何快速接入Keycloak的示例。javascript
Keycloak是一种面向现代应用和服务的开源IAM(身份识别与访问管理)解决方案前端
Keycloak提供了单点登陆(SSO)功能,支持OpenID Connect
、OAuth 2.0
、SAML 2.0
标准协议,拥有简单易用的管理控制台,并提供对LDAP、Active Directory以及Github、Google等社交帐号登陆的支持,作到了很是简单的开箱即用。vue
首先经过官方的一张图来了解下总体的核心概念java
这里先只介绍4个最经常使用的核心概念:react
Users
: 用户,使用并须要登陆系统的对象ios
Roles
: 角色,用来对用户的权限进行管理git
Clients
: 客户端,须要接入Keycloak并被Keycloak保护的应用和服务github
Realms
: 领域,领域管理着一批用户、证书、角色、组等,一个用户只能属于而且能登录到一个域,域之间是互相独立隔离的, 一个域只能管理它下面所属的用户web
Keycloak安装有多种方式,这里使用Docker进行快速安装spring
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方案。
本文示例项目地址:keycloak-demo