Code前端首页关于Code前端联系我们

.env.development

terry 1天前 阅读数 19 #Vue

现在前后端分离项目里,权限管理和用户认证越来越复杂,尤其是多个系统间的单点登录、角色权限控制这些需求,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:填前端域名,解决跨域,开发时可以先填 (生产要限制);
  • 给 Client 分配角色adminuser),再给测试用户分配角色(Keycloak 里创建用户,加角色映射)。

前端 Vue2 项目装依赖、写鉴权逻辑

第一步:装 keycloak-js 库,命令行执行 npm install keycloak-js

第二步:封装 Keycloak 实例,在 src/utils/keycloak.js 里写:

```javascript import Keycloak from '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 里配置路由元信息,再加导航守卫:

```javascript import { createRouter, createWebHistory } from 'vue-router' import Home from '../views/Home.vue' import Admin from '../views/Admin.vue' import keycloak from '../utils/keycloak'

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-requiredcheck-sso,让它自动处理登录态;
  • 前端路由模式(history 或 hash)要和 Keycloak 的 redirectUri 匹配,比如用 history 模式,redirectUri 得是 http://xxx.com/path,不能是带 的。

怎么用 Keycloak 给 Vue2 做角色和细粒度权限?

权限控制分“页面级”“接口级”,Keycloak 都能覆盖:

页面级权限:哪些页面能进?哪些按钮能点?

前面路由守卫的例子是“页面级”控制(/admin 只有 admin 能进),如果是按钮级(删除”按钮只有管理员能点),可以这么做:

  • 在 Vue 组件里,通过 keycloak.userInfo().roles 获取用户角色;
  • v-if 控制按钮显示:
```vue ```

接口级权限:后端接口要不要放行?

后端得配合 Keycloak 做鉴权,以 Spring Boot 为例:

  • 引入 keycloak-spring-boot-starter 依赖;
  • 配置 application.yml,指定 Keycloak 的 realm、client、公钥等;
  • @RolesAllowed@PreAuthorize 注解保护接口:
```java @RestController @RequestMapping("/api") public class UserController {
@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 会失败,这时要跳转到登录页重新授权:

```javascript router.beforeEach(async (to, from, next) => { try { await keycloak.updateToken(5) next() } catch (error) { // 刷新失败,强制登录 keycloak.login() } }) ```

还要注意前后端时间同步!Keycloak 服务端和前端/后端服务器时间差太大,会导致 token 明明没过期,却被判定为无效,所以要确保所有服务的时间一致(比如用 NTP 同步)。

多环境(开发/测试/生产)下,Vue2 咋配不同的 Keycloak 实例?

不同环境的 Keycloak 地址、realm、clientId 都不一样,得用 Vue 的环境变量来管理:

新建环境变量文件

在项目根目录下,创建:

  • .env.development(开发环境)
  • .env.production(生产环境)
示例(开发环境用本地 Keycloak):

```bash VUE_APP_KEYCLOAK_URL=http://localhost:8080 VUE_APP_KEYCLOAK_REALM=my-company-dev VUE_APP_KEYCLOAK_CLIENT_ID=vue2-app-dev ```

生产环境用线上 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前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门