其他分享
首页 > 其他分享> > Keycloak 入门使用

Keycloak 入门使用

作者:互联网

Keycloak入门使用

简介

Keycloak 为现代应用和分布式服务提供了一套完整的认证授权管理解决方案,它是开源的,是一个独立的认证授权服务器。它主要是基于OAuth2协议的实现,同时提供了多种语言库,让我们可以很快速地根据我们的需求将Keycloak集成到我们的项目中去使用。

这里主要介绍Keycloak的一些基本使用实践,在学习Keycloak之前,最好要先了解OAuth2的协议流程,否则比较难以理解keycloak的认证过程。在熟悉了OAuth2协议以后去学习Keycloak,其实就很简单了。

若想了解OAuth2协议,可以看这篇 理解OAuth2协议

下面列出的是我所知道的Keycloak相关的内容,下面会详细介绍其中的某一些

安装 & 启动服务器

专有名词 & 基本使用

当你启动的keyclaok服务器,然后使用admin账号登录以后,进去到keycloak管理页面:
在这里插入图片描述
这是Master Realm的settings页面,Master Realm是keycloak默认有的realm,顾名思义就是用于管理的realm,例如admin这个用户就是属于这个realm:
在这里插入图片描述
那Realm是什么意思呢?Realm字面意思是领域,指的是在某一个软件业务领域中所涉及的用户认证授权管理相关的对象,在这个realm下有用户、角色、会话(session)等等用于认证授权管理的对象。

假设一个公司A使用一个ERP系统,那么就可以给这个公司A设置一个Realm,用于该公司所有员工的授权管理。那么如果另一个公司B也使用这个ERP系统(假设这个ERP系统是第三方提供给所有公司使用的一个ERP服务,就需要给公司B也创建一个Realm,用于公司B员工的授权管理。

所以Realm之间的相互隔离的一个业务领域概念。

集成Keycloak

在这里插入图片描述
假设我们有两个web服务器,我们需要使用keycloak来对我们的资源进行保护,只有用户登录以后才能访问到这两个服务器的资源,否则就要跳转到登录页面。所以我们要在两个服务之前加一个gateway层,在这一层对用户请求进行拦截,验证用户是否已经登录(了解OAuth2的话,就知道这里就是验证accessToken),如果没有的话,就要引导用户去到keycloak登录页面,认证以后再跳转回到要访问的页面。

因此,我们已经启动了keycloak服务器,缺少的是怎么将拦截用户请求并验证accessToken这些逻辑加入到我们的应用中。别急,keycloak官方给我们提供了这些库,它把这个东西叫做 adaptor(connector),所以我们只要将这些库安装到我们的项目中就可以为我们的应用实现认证授权。

这里呢,我实践的是给nodejs server集成keycloak认证授权,所以以下介绍的是 Nodejs-keycloak-adaptor.
keycloak-nodejs-adaptor 我也是参考官方的例子去实现的。
另外keycloak官方有一些quickstart的最佳实践,参考:keycloakQuickstart

点击Save,然后切换到最后一栏installation,拿到client的连接信息:
在这里插入图片描述

  1. 使用npm init初始化一个nodejs项目,加入如下依赖:
	"body-parser": "^1.13.3",
    "cors": "^2.8.1",
    "express": "^4.13.3",
    "express-session": "^1.14.2",
    "jsonwebtoken": "^8.5.1",
    "keycloak-admin": "^1.13.0",
    "keycloak-connect": "11.0.2",

其中keycloak-connect就是集成keycloak的连接库

  1. 新建一个keycloak-config.js,将你的的installation连接信息替换替换对应的属性,例如上面的信息就是:
module.exports = {
  realm: 'myRealm',
  authServerUrl: 'http://localhost:8080/auth/',
  clientId: 'testClient',
  credentials: {
    secret: '4434b959-835b-45c9-bed5-607e025e0100'
  },
  bearerOnly: false
}

authServerUrl记得最后加上/,这里是一个坑,不加可能报错。以上拿到的连接信息,其实resource就是clientId,对应OAuth2中的clientId和clientSecret(credentials.secret)。所以说,如果你熟悉OAuth2,来到这里很容易就知道看到这就是client必须要有的基本信息。

  1. 新建一个app-express.js (名字随你)

直接贴出全部代码:

const express = require('express');
const path = require('path');
const bodyParser = require('body-parser')
const session = require('express-session')
const KeycloakConnect = require('keycloak-connect')
const keycloakConfig = require('./keycloak-config')
const jwt = require('jsonwebtoken')
const  router = express.Router();

// keycloak
const memoryStore = new session.MemoryStore();
const keycloak = new KeycloakConnect({store: memoryStore}, keycloakConfig)

const app = express();
app.use(bodyParser.json());

app.use(session({
    secret: 'some secret',
    resave: false,
    saveUninitialized: true,
    store: memoryStore
}));

app.use(keycloak.middleware({
    logout: '/logout',
    admin: '/'
}));

// api settings
router.get('/service/public', (req, res) => {
    res.json({message: 'public'});
});
router.get('/service/secured', keycloak.protect('realm:USER'), function (req, res) {
    res.json({message: 'secured'});
});

const keycloakProtect = keycloak.protect()
router.get('*', (req, resp, next) => {
    const originalUrl = req.originalUrl
    if (originalUrl.indexOf('abc') > -1 || originalUrl === '/' || originalUrl.indexOf('favicon.ico') > -1) {
        return next()
    }
    return keycloakProtect(req, resp, next)
}, (req, resp, next) => {
    const keycloakToken = req.session['keycloak-token']
    let userId = 'test'
    if (keycloakToken) {
        userId = jwt.decode(JSON.parse(keycloakToken).access_token).preferred_username
    }
    const cookiesOption = {
        maxAge: 1000 * 60 * 60 * 24,
        httpOnly: false
    }
    resp.cookie('user_id', userId, cookiesOption)
    return next()
})

app.use(router)
// static resources
app.use(express.static(path.join(__dirname, '/views')));


app.listen(3001, () => {
    console.log('Started at port 3001');
});

这里是使用express启动一个nodejs server

const keycloak = new KeycloakConnect({store: memoryStore}, keycloakConfig)

const app = express();
app.use(bodyParser.json());

app.use(session({
    secret: 'some secret',
    resave: false,
    saveUninitialized: true,
    store: memoryStore
}));

app.use(keycloak.middleware({
    logout: '/logout',
    admin: '/'
}));

新建KeycloakConnect对象,传进去sessionStore以及keycloakConfig。注意这里keycloak的store使用的是express-session的store,因为认证成功以后keycloak就会将所有的token的信息存储在session中。

最后就是use keycloak提供的中间件,查看这些中间源码你就会知道,这些中间件所做的事情其实就是首先会从session拿出accessToken,然后认证accessToken的有效性等等。

keycloak.protect()

keycloak.protect() 在你的router api中加入这个中间件,就能够对你这个API进行认证保护,后面的代码相信大家一看就明白了,这里不多说。(Talk is cheap, show you the code)

完整代码查看:github (有些代码没有放出来)
运行项目,访问http://localhost:3000/,可以正常访问;访问http://localhost:3000/work.html,会跳转到登录页面。
在这里插入图片描述

理解运行流程

那么对应上面的这个例子呢,可能你确实能成功保护你的资源了,但是我们有必要去理解一下整一个认证过程,这个验证过程其实就是OAuth2的授权码模式:
在这里插入图片描述

在第2步,web server将用户导向keycloak server的重定向连接:
http://localhost:8080/auth/realms/myRealm/protocol/openid-connect/auth?client_id=nodejs&state=10abdacb-5e85-4f48-8bf7-b8aedb378567&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fwork.html%3Fauth_callback%3D1&scope=openid&response_type=code
可以看到使用的就是OAuth2授权码模式:response_type=code

在第3步中keycloak-server将用户导向回web-server的重定向连接:
http://localhost:3001/work.html?auth_callback=1&state=10abdacb-5e85-4f48-8bf7-b8aedb378567&session_state=3f47f74a-ef0c-4245-b87e-22acae8b08e9&code=281cd9c6-187e-423f-84ee-9419aa4dab7d.3f47f74a-ef0c-4245-b87e-22acae8b08e9.aa9ee788-cbb7-4370-9ed2-6de8b2b510b7

Reference

https://github.com/keycloak
https://www.keycloak.org/

标签:const,入门,app,express,认证,session,使用,Keycloak,keycloak
来源: https://blog.csdn.net/little_kelvin/article/details/111239241