接上文《Keycloak通用接入手册(以Java为例)》,前面所述的,都是针对于服务器端的接入说明。
而现代化的前端技术,已经具备了很强大的native处理能力,很幸运,Keycloak已经提供JavaScript Adapter,它可以用于现代化的前端、移动端APP接入,GitHub上可以找到很多 VueJS、ReactJS、React Native的接入例子。
下面以 VueJS APP为例,说明如何接入。
主要参考的官方教程:javascript-adapter-reference。
首先教程中说明一点:One important thing to note about using client-side applications is that the client has to be a public client as there is no secure way to store client credentials in a client-side application.
另外,据我所知,纯前端JS的权限控制,不应该作为安全控制的手段,后端APP还是需要做权限控制。
比如,一个前后端分离的项目,前端 部署在端口为9999的服务器上,后端部署在 8080的服务器上,对Keycloak而言,这个两个不同的服务器,两个URL,对应于两个不同的client,所以,首先要在keycloak上新建两个client,基本信息如下:
服务器端的client:
{ clientId: 'backend-app', root-url: 'http://localhost:8080/myapp', Access_Type: private, secret: d4589683-0ce7-4982-bcd3-c48a12572f79 }
前端的client:
{ clientId: 'frontend-app', root-url: 'http://{ip}:9999', Access_Type: public }
注意,前端client是public没有密码的,因为前面说了,前端接入keycloak的目的,并不是为了做安全控制,而且前端存放密码没有安全意义。
JS Adapter原理如下:
keycloak.js会在页面嵌入一个 loginFrame,然后使用JS循环不断的检查token状态,如果没有token(没登录或者已登出),则会调用 kc.login方法使用 window.location.replace(ssoLoginUrl)的方式跳转到登录页面。同理退出登录的话,会调用kc.logout方法跳转。(详见 keycloak.js 源码)
与VueJS APP接入的要点如下:
在每个单独的页面,引入keycloak并做初始化(以便建立起loginFrame)。
废掉之前的登录页面,以及登录拦截器(比如vue router里面的),因为它们已经没有作用了。
关于用户信息,只能从keycloak.js获得用户名,更详细的信息,建议还是调后端api从数据库获取。
以Vue UI框架为例,步骤如下:
1)第一步:npm install @dsb-norge/vue-keycloak-js --save
2)第二步:在main.js里面添加:
import VueKeyCloak from '@dsb-norge/vue-keycloak-js' // You can also pass in options. Check options reference below. Vue.use(VueKeyCloak, options)
配置好options即可,按照这个组件的教程:https://www.npmjs.com/package/@dsb-norge/vue-keycloak-js,把 new Vue(...) 放到onReady里面。如下所示:
Vue.use(VueKeyCloak, { config: { realm: 'demo', url: 'http://localhost:8180/auth/', clientId: 'fastvue', logoutRedirectUri: 'http://localhost:9527/#/login' }, onReady: (keycloak) => { new Vue({ el: '#app', router, store, i18n, render: h => h(App) }) } })
3)第三步(非必须,视项目情况),修改原来的vue router
比如我的是在permission.js里面,有个router.beforeEach((to, from, next),把它的登录判断逻辑改成
if (Vue.prototype.$keycloak.authenticated) { // 已登录 // TODO }
4)第四步,修改 退出登录的 逻辑。
我是把原来退出方法的直接改成:
logout () { ... Vue.prototype.$keycloak.logoutFn() }
这样就OK了,它会调用 window.location 跳转登录页面去。
前、后端项目对接
前面分别把 前端 和 后端 对接了Keycloak,那么怎么把前后端连接起来呢?
思路如下:前端登录keycloak后,立即去后端登录一下,这样才能获得后端的session或token。
第一步:
1)如果用的是token登录,则写一个sso登录的接口,前端调用后,得到这个token,然后每次请求带上这个token就行了。
Fast Vue框架为例,改动如下:
在调用GetUserInfo之前,增加一个调用SSO Login API登录,登录后将token保存下来。
2)如果用的是session(cookie)登录,则配置 AJAX的 withCredentials = true,这样每次请求都会带上登录的cookie信息。
以Fast Admin 和 Fast Vue框架为例,改动如下:
在前端ajax配置中,加上withCredentials = true
axios.create({ baseURL: base_url, timeout: 5000, withCredentials: true })
相应地,后端corsFilter(org.springframework.web.cors.CorsConfiguration)中也要加上:
config.setAllowCredentials(true);
提醒,如果没有加 AllowedOrigin,也一定要加上,例如:
config.addAllowedOrigin("http://localhost:9527") // 前端的地址
如果不懂Cors(跨域请求),参见这篇文章:http://newhtml.net/using-cors/
第二步:
在后端keycloak配置中,加入
keycloak.cors=true
总结:
以Fast Vue框架为例,总共5个步骤:
npm install @dsb-norge/vue-keycloak-js --save
在main.js里面配置vue-keycloak
修改router,把以前的登录判断逻辑,改成根据keycloak状态来判断
修改 退出登录的 逻辑,直接调用$keycloak.logoutFn()
废掉原来的登录页面和代码,改成调用后端的sso-login API,获得token后保存即可
下面再提供两个例子:
ReactJS例子:
https://github.com/dasniko/keycloak-reactjs-demo
AngularJS例子:
https://github.com/iuliazidaru/keycloak-spring-boot-rest-angular-demo
更多例子参见GitHub:
https://github.com/search?l=JavaScript&p=2&q=keycloak&type=Repositories
更多细节参见官方文档:
https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter