技术标签: spring boot java vue sso
登录及身份认证是现代web应用最基本的功能之一,对于企业内部的系统,多个系统往往希望有一套SSO服务对企业用户的登录及身份认证进行统一的管理,提升用户同时使用多个系统的体验,Keycloak正是为此种场景而生。本文将简明的介绍Keycloak的安装、使用,并给出目前较流行的前后端分离应用如何快速接入Keycloak的示例。
Keycloak是一种面向现代应用和服务的开源IAM(身份识别与访问管理)解决方案
Keycloak提供了单点登录(SSO)功能,支持OpenID Connect
、OAuth 2.0
、SAML 2.0
标准协议,拥有简单易用的管理控制台,并提供对LDAP、Active Directory以及Github、Google等社交账号登录的支持,做到了非常简单的开箱即用。
首先通过官方的一张图来了解下整体的核心概念
这里先只介绍4个最常用的核心概念:
Users
: 用户,使用并需要登录系统的对象
Roles
: 角色,用来对用户的权限进行管理
Clients
: 客户端,需要接入Keycloak并被Keycloak保护的应用和服务
Realms
: 领域,领域管理着一批用户、证书、角色、组等,一个用户只能属于并且能登陆到一个域,域之间是互相独立隔离的, 一个域只能管理它下面所属的用户
Keycloak安装有多种方式,这里使用Docker进行快速安装
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方案。
文章浏览阅读3.8k次。在java中,static关键字代表的含义为"静态的",只要在方法或者属性前面加上了static关键字,这个方法或属性就属于类了,如果没有static关键字,方法或属性是属于这个类的对象。我们称加上static关键字的属性和方法为静态属性和静态方法,不加static关键字的属性和方法我们称为为普通属性和普通方法。普通属性和普通方法可以随着对象的多次创建而被重复使用,而静态属性和静态变量是唯一的,只..._静态内部类中的静态属性可以直接访问吗
文章浏览阅读4.6k次,点赞11次,收藏28次。前言: echarts实现西安地铁图效果图:官网入口实现代码:var data = [ { name: "地铁一号线", tooltip: { formatter: "{b}: 19999<br />" }, symbolSize: 0.1, value: [5, 750], x: 800, ..._echarts地铁图
文章浏览阅读155次。类型 速率 距离 标准 编码 工作模式 10BASE-T UTP 10Mbps 100m IEEE802.3i 10BASE-2 200m 10BASE-5 500m 100Base-TX UTP-5类或匹配电阻为150Ω的STP 100Mbps 100M IEEE802.3 4B/5B曼_等比例压缩传输和变比例传输的区别
文章浏览阅读307次。这里写自定义目录标题页面设计全局三个文件Pages 目录文件创建页面把内容单元封装在view内部插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入页面设计全局三个文件分别是app.jsapp.jsonapp.wxss名称不可更改Pages 目录文件用来放各个页面的标_进公司第一天写微信小程序的项目
文章浏览阅读1.4k次。(只有气到我肺都炸了的情况下我才可能废一些时间去写博客(主要是写一些气话),但现在气消得差不多了我也骂不出什么话了。正文1、字符串拼接分软拼接和硬拼接(“软硬拼接”是我自己发明的词~实际上到底有没有这种说法我就没去管了)2、所谓软拼接,就是字符串后面加的是【字符串】;硬拼接就字符串后面加的是【字符】 3、软拼接,只会拼接'\0'之前的有效字符;硬拼接,是什么字符都能硬加进去,包括'\0'4、硬拼接如果拼接的是'\0',在判等的时候很大概率翻车。(在map的find函数里会要用到判等的。没错我就这翻_c++字符串拼接缺失
文章浏览阅读86次。当服务器遇到性能瓶颈需要进行扩展时,一般来说有两种解决思路:Scale-up 和 Scale out,也称作垂直扩展和水平扩展。常见的负载均衡器根据工作在的协议层划分可划分为:四层负载均衡:根据请求报文中的目标地址和端口进行调度七层负载均衡:根据请求报文的内容进行调度,这种调度属于「代理」的方式根据软硬件划分:硬件负载均衡:F5 的 BIG-IPCitrix 的 NetSca...
文章浏览阅读339次。链表二叉树链接如下sdut oj 数据结构实验之二叉树五:层序遍历 (链表).数组模拟方式见下文Description已知一个按先序输入的字符序列,如abd,eg,cf,(其中,表示空结点)。请建立二叉树并求二叉树的层次遍历序列。Input输入数据有多行,第一行是一个整数t (t<1000),代表有t行测试数据。每行是一个长度小于50个字符的字符串。Output输出二叉树的层次遍历序列。SampleInput2abd,,eg,,,cf,,,xnl,,i,,u,,Outpu_数组模拟树的层次遍历
文章浏览阅读598次。ListView分页加载数据ListView分页加载 在Android中是一个经常用到的技术,当我们需要加载大量的数据到列表显示时,假如一次性把所有数据加载完毕,可能会导致整个ListView列表卡顿,给用户的体验也非常不好。因而,我们可以将数据分为多次加载,每次加载其中的一部分,用户有需求的时候再加载其他部分,这样的设计会更加友好。 ListView分页原理在日常开发中,我们可能会遇到以下两种情_listview按页请求数据
文章浏览阅读1.5w次,点赞5次,收藏37次。1.通过请求获取权限,放入localStorage:(这里是多个权限,保存为字符串,用逗号隔开)window.localStorage.setItem("permissionPage", "editPage,detailPage");window.localStorage.setItem("permissionButton", "canEdit,canDelete");2.在main.ts中引入:import hasPermission from '@/common/utils/hasPermi_v-has
文章浏览阅读6.8k次,点赞8次,收藏23次。分析乘法表发现,整体有九行,第一行是一列,第二行是两列,第三行三列.....第九行对应有九列,所以它的行数对应就有多少列,这样我们可以通过借助行数来控制它的列数,以此来实现乘法表的打印。具体代码实现:for循环public class MultTable { public static void main(String[] args) { //此处调用九九乘法表方法实现打印 multMethod(); } public static void multMethod() { /_java用循环和分支结构写九九乘法表
文章浏览阅读6.1k次。运算符概述1) 算术运算符执行算术运算,例如:加、减、乘、除等。2) 比较运算符包括大于、小于、等于或不等于、等等。主要用于数值的比较、字符串的匹配等方面。3) 逻辑运算符包括与、或、非和异或、等逻辑运算符。其返回值为布尔型,真值(1 或 true)和假值(0 或 false)。4) 位运算符包括按位与、按位或、按位取反、按位异或、按位左移和按位右移等位运算符。位运算必须先将数据转换为补码,然后在根据数据的补码进行操作。运算完成后,将得到的值转换为原来的类型(十进制数),返回_数据库运算符
文章浏览阅读87次。龙芯软件开发(24)-- PCI设备初始化2 ..._龙芯pci中断绑定