.env.development
现在前后端分离项目里,权限管理和用户认证越来越复杂,尤其是多个系统间的单点登录、角色权限控制这些需求,Vue2 作为曾经的主流前端框架,结合 Keycloak 这个开源身份认证工具,能高效解决这些问题,但很多同学刚开始接触时,总会疑惑“Vue2 项目里咋用 Keycloak 做权限管理?流程是啥?遇到问题咋解决?” 这篇文章就从基础到实战,用问答形式把这些关键点讲透。
Keycloak 是啥?和 Vue2 结合能解决哪些痛点?
先搞清楚 Keycloak 定位:它是开源的身份验证和授权平台,能帮我们快速实现单点登录(SSO)、用户认证、角色权限控制,还支持 OAuth2、OpenID Connect、SAML 这些协议。
Vue2 是前端框架,负责页面渲染和交互,两者结合后,能解决这些场景:
- 单点登录(SSO):企业内部有多个系统(比如后台管理、客户门户),用户登录一次 Keycloak,所有关联的 Vue2 项目都能免登,不用重复输密码。
- 用户认证 & 授权:前端路由、页面按钮要不要显示,后端接口能不能访问,都靠 Keycloak 发的 token 和角色信息做判断。
- 协议落地:不用自己手写 OAuth2/OpenID Connect 逻辑,Keycloak 帮我们处理 token 生成、刷新、验证这些“脏活”。
举个例子:公司有 A、B 两个 Vue2 项目,都集成 Keycloak 且属于同一个 realm(Keycloak 里的“领域”,类似租户),用户在 A 登录后,打开 B 项目时,Keycloak 会检测到已有登录态,自动让 B 拿到权限,用户不用再输账号密码。
Vue2 集成 Keycloak 的核心步骤是啥?
核心流程分服务端配置(Keycloak 后台)和前端代码(Vue2 项目)两部分,一步步拆:
先把 Keycloak 服务搭起来,配置基础信息
如果是本地测试,先下载 Keycloak 包(官网能下),启动后访问管理控制台(默认 http://localhost:8080/admin
),步骤:
- 创建 Realm(相当于租户,比如叫“my-company”);
- 在 Realm 里创建 Client(对应前端 Vue2 项目,比如叫“vue2-app”);
- Client 配置关键项:
- Access Type:选
public
(前端项目属于公共客户端,不需要客户端密钥); - Valid Redirect URIs:填前端项目的回调地址,比如开发环境是
http://localhost:8080/*
( 是通配符,生产要写具体路径); - Web Origins:填前端域名,解决跨域,开发时可以先填 (生产要限制);
- Access Type:选
- 给 Client 分配角色(
admin
、user
),再给测试用户分配角色(Keycloak 里创建用户,加角色映射)。
前端 Vue2 项目装依赖、写鉴权逻辑
第一步:装 keycloak-js
库,命令行执行 npm install keycloak-js
。
第二步:封装 Keycloak 实例,在 src/utils/keycloak.js
里写:
// 根据环境变量配置(后面讲多环境配置时细说)
const keycloakConfig = {
url: 'http://localhost:8080', // Keycloak 服务地址
realm: 'my-company', // 刚才建的 Realm
clientId: 'vue2-app' // 刚才建的 Client
}
const keycloak = new Keycloak(keycloakConfig)
export default keycloak
<p>第三步:在 <code>main.js</code> 里初始化 Keycloak,控制应用启动逻辑:</p>
```javascript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import keycloak from './utils/keycloak'
// 初始化 Keycloak,onLoad: 'login-required' 表示“没登录就跳登录页”
keycloak.init({ onLoad: 'login-required' }).then((authenticated) => {
if (authenticated) {
const app = createApp(App)
app.use(router)
app.mount('#app')
console.log('Keycloak 初始化成功,用户已登录')
} else {
// 初始化成功但未认证,强制登录
keycloak.login()
}
}).catch((error) => {
console.error('Keycloak 初始化失败:', error)
})
路由守卫控制页面权限
比如某些页面(如 /admin
)只有 admin
角色能进,在 router/index.js
里配置路由元信息,再加导航守卫:
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/admin',
name: 'Admin',
component: Admin,
meta: { requiresRole: 'admin' } // 标记需要 admin 角色
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
// 导航守卫:每次跳转前检查角色
router.beforeEach(async (to, from, next) => {
if (to.meta.requiresRole) {
// 获取用户角色(keycloak.userInfo() 能拿到用户信息,包括 roles)
const userInfo = await keycloak.userInfo()
const userRoles = userInfo.roles || []
if (userRoles.includes(to.meta.requiresRole)) {
next()
} else {
// 没有权限,跳首页或403页
next({ name: 'Home' })
}
} else {
next()
}
})
export default router
#### 4. 接口请求带 token(以 axios 为例)
<p>前端调后端接口时,要把 Keycloak 的 token 放到请求头里(<code>Authorization: Bearer + token</code>),在 <code>src/utils/request.js</code> 里封装 axios:</p>
```javascript
import axios from 'axios'
import keycloak from './keycloak'
const service = axios.create({
baseURL: '/api', // 后端接口基础路径
timeout: 5000
})
// 请求拦截器:加 token
service.interceptors.request.use(
(config) => {
const token = keycloak.token
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => {
return Promise.reject(error)
}
)
export default service
到这一步,基本的“登录拦截 + 角色控制 + 接口鉴权”就跑通了。
集成时遇到“初始化失败”“跨域”这些坑咋填?
新手最容易栽在这些细节上,逐个说解法:
Keycloak 初始化 Promise 一直 reject
常见原因:
- 服务没启动:先确认 Keycloak 服务是否正常运行(访问
http://localhost:8080
能打开登录页吗?); - 配置写错:realm 名、clientId 是不是和 Keycloak 后台一致?realm 是“my-company”,别写成“mycompany”(大小写敏感);
- redirectUri 不匹配:前端项目的启动地址和 Client 里的
Valid Redirect URIs
对不上,比如前端跑的是http://localhost:3000
,但 Client 里配的是http://localhost:8080/*
,就会失败。
解法:逐个检查这三项,确保服务启动、配置一致、redirectUri
包含前端地址。
跨域(CORS)问题,浏览器报“Access to XMLHttpRequest at ... from origin ... has been blocked by CORS policy”
分两种场景处理:
- Keycloak 服务端跨域:前端调 Keycloak 的登录、token 接口时跨域,解决:在 Keycloak 的 Client 配置里,Web Origins 加上前端域名(
http://localhost:8080
),多个域名用逗号分隔,开发时可以先填 (生产别这么干,不安全); - 后端接口跨域:前端调自己后端接口时跨域,解决:后端要配置 CORS,允许前端域名,并且允许
Authorization
头(因为要传 Bearer token),Spring Boot 里加@CrossOrigin
注解,或用 Filter 配置。
登录后跳转到前端,页面白屏或路由不对
原因:Keycloak 登录成功后,会把用户重定向到前端的 redirectUri
,但前端路由没处理好,解法:
- 确保
Valid Redirect URIs
包含前端的路由模式(比如哈希路由要带 ,历史路由要配正确的base
); - Keycloak 初始化时,
onLoad
配置成login-required
或check-sso
,让它自动处理登录态; - 前端路由模式(history 或 hash)要和 Keycloak 的
redirectUri
匹配,比如用 history 模式,redirectUri
得是http://xxx.com/path
,不能是带 的。
怎么用 Keycloak 给 Vue2 做角色和细粒度权限?
权限控制分“页面级”和“接口级”,Keycloak 都能覆盖:
页面级权限:哪些页面能进?哪些按钮能点?
前面路由守卫的例子是“页面级”控制(/admin
只有 admin
能进),如果是按钮级(删除”按钮只有管理员能点),可以这么做:
- 在 Vue 组件里,通过
keycloak.userInfo().roles
获取用户角色; - 用
v-if
控制按钮显示:
接口级权限:后端接口要不要放行?
后端得配合 Keycloak 做鉴权,以 Spring Boot 为例:
- 引入
keycloak-spring-boot-starter
依赖; - 配置
application.yml
,指定 Keycloak 的 realm、client、公钥等; - 用
@RolesAllowed
或@PreAuthorize
注解保护接口:
@GetMapping("/admin-only")
@RolesAllowed("admin") // 只有 admin 角色能访问
public String adminOnly() {
return "只有管理员能看到~";
}
<p>前端调这个接口时,只要在请求头带合法 token,后端就会校验角色,返回对应结果。</p>
### 五、Keycloak 的 token 过期了咋处理?Vue2 里咋自动刷新?
<p>Keycloak 的 token 有过期时间(默认 30 分钟),过期后请求会被后端拒绝,但 <code>keycloak-js</code> 提供了自动刷新机制:</p>
#### 1. 自动刷新的原理
<p>Keycloak 会在 token<strong>快过期时(默认提前 30 秒)</strong>,自动用 <code>refresh_token</code> 去换新的 <code>access_token</code>,前端不用手动写逻辑,只要 <code>keycloak.init()</code> 后,实例会自动管理 token 生命周期。</p>
#### 2. 手动控制刷新(可选)
<p>如果想更主动(比如路由跳转前检查 token),可以用 <code>keycloak.updateToken(minValidity)</code> 方法,比如在导航守卫里:</p>
```javascript
router.beforeEach(async (to, from, next) => {
// token 剩余时间小于 5 秒,就刷新
const refreshed = await keycloak.updateToken(5)
if (refreshed) {
console.log('token 刷新成功')
} else {
console.log('token 还没到刷新时间')
}
next()
})
处理刷新失败的情况
refresh_token
也过期了,updateToken
会失败,这时要跳转到登录页重新授权:
还要注意前后端时间同步!Keycloak 服务端和前端/后端服务器时间差太大,会导致 token 明明没过期,却被判定为无效,所以要确保所有服务的时间一致(比如用 NTP 同步)。
多环境(开发/测试/生产)下,Vue2 咋配不同的 Keycloak 实例?
不同环境的 Keycloak 地址、realm、clientId 都不一样,得用 Vue 的环境变量来管理:
新建环境变量文件
在项目根目录下,创建:
.env.development
(开发环境).env.production
(生产环境)
生产环境用线上 Keycloak:
```bash # .env.production VUE_APP_KEYCLOAK_URL=https://keycloak.mycompany.com VUE_APP_KEYCLOAK_REALM=my-company-prod VUE_APP_KEYCLOAK_CLIENT_ID=vue2-app-prod ```在代码里动态读取环境变量
修改 <
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。