• Keycloak快速上手指南,只需10分钟即可接入Spring Boot/Vue前后端分离应用实现SSO单点登录


    登录及身份认证是现代web应用最基本的功能之一,对于企业内部的系统,多个系统往往希望有一套SSO服务对企业用户的登录及身份认证进行统一的管理,提升用户同时使用多个系统的体验,Keycloak正是为此种场景而生。本文将简明的介绍Keycloak的安装、使用,并给出目前较流行的前后端分离应用如何快速接入Keycloak的示例。

    Keycloak是什么

    Keycloak是一种面向现代应用和服务的开源IAM(身份识别与访问管理)解决方案

    Keycloak提供了单点登录(SSO)功能,支持OpenID ConnectOAuth 2.0SAML 2.0标准协议,拥有简单易用的管理控制台,并提供对LDAP、Active Directory以及Github、Google等社交账号登录的支持,做到了非常简单的开箱即用。

    Keycloak常用核心概念介绍

    首先通过官方的一张图来了解下整体的核心概念

    keycloak-core-concepts

    这里先只介绍4个最常用的核心概念:

    1. Users: 用户,使用并需要登录系统的对象

    2. Roles: 角色,用来对用户的权限进行管理

    3. Clients: 客户端,需要接入Keycloak并被Keycloak保护的应用和服务

    4. Realms: 领域,领域管理着一批用户、证书、角色、组等,一个用户只能属于并且能登陆到一个域,域之间是互相独立隔离的, 一个域只能管理它下面所属的用户

    Keycloak服务安装及配置

    安装Keycloak

    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进行登录

    keycloak-web-home

    创建Realm

    创建一个新的realm: demo,后续所有的客户端、用户、角色等都在此realm中创建

    keycloak-web-add-realm-1

    keycloak-web-add-realm-2

    keycloak-web-add-realm-3

    创建客户端

    创建前端应用客户端

    创建一个新的客户端:vue-demo,Access Type选择public

    keycloak-web-add-client-1

    创建后端应用客户端

    创建一个新的客户端:spring-boot-demo,Access Type选择bearer-only

    keycloak-web-add-client-2

    保存之后,会出现Credentials的Tab,记录下这里的secret,后面要用到

    keycloak-web-add-client-3

    关于客户端的访问类型(Access Type)

    上面创建的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

    keycloak-web-add-role

    创建用户

    创建2个用户:admin、customer

    keycloak-web-add-user

    绑定用户和角色

    给admin用户分配角色ROLE_ADMIN

    keycloak-web-add-user-role-1

    给customer用户分配角色ROLE_CUSTOMER

    keycloak-web-add-user-role-2

    Vue应用集成Keycloak简明指南

    创建vue项目

    vue create vue-demo
    

    添加官方Keycloak js适配器

    npm i keycloak-js --save
    npm i axios --save
    

    main.js

    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)
    })
    

    HelloWorld.vue

    <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

    Spring Boot应用集成Keycloak简明指南

    添加Keycloak Maven依赖

    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-starter</artifactId>
        <version>10.0.0</version>
    </dependency>
    

    Spring Boot配置文件

    官方文档及网上大部分示例使用的都是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角色的用户才能访问
    • 未配置的路径表示公开访问

    Controller内容

    @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前端项目

    第一次访问vue项目会跳转Keycloak登录页

    keycloak-demo-1

    登录admin用户

    keycloak-demo-2

    登录customer用户

    keycloak-demo-3

    总结

    Keycloak部署及接入简单,轻量的同时功能又不失强大,非常适合企业内部的SSO方案。

    本文示例项目地址:keycloak-demo

  • 相关阅读:
    另一种遍历Map的方式: Map.Entry 和 Map.entrySet()
    mycat 插入语句导致的一个Dobbo问题
    Json数据处理
    List与字符串转换
    MySQL中四舍五入的实现
    java连接mysql :No Suitable Driver Found For Jdbc 解决方法
    Linux中printf格式化输出
    bat隐藏文件夹
    Python 3.5.2建立与DB2的连接
    Python 爬虫实例
  • 原文地址:https://www.cnblogs.com/vigoz/p/12984556.html
Copyright © 2020-2023  润新知