一款强大的开源认证和访问控制利器:KeyCloak

admin 2024-01-21 28次阅读

是不是非常简单呢?

注销

tokenpocet官网

注销也非常简单只需执行.()方法即可注销。

tokenrank官网

示例代码:

@RestController
public class LogoutController {
    @GetMapping("/logout")
    public String logout(HttpServletRequest request) throws ServletException {
        request.logout();
        return "退出成功";
    }
}

邮箱配置

参考下图的配置,即可实现邮件发送。

tokenrank官网_token 权限管理·(中国)官方网站_tokenpocet官网

默认的邮件模板详见$//base/email/html,是用写的。我们也可以自定义邮件模板,详见“主题定制”一节。

与 Cloud整合

经过上文的讲解,我们已实现整合 Boot应用。那么,在一个使用 Cloud构建的分布式应用中,要如何整合呢?——即:A微服务信任的Token要如何传递给B微服务呢?

下面我们分两种场景:

使用Feign传递Token

下面我们创建一个新的微服务ms--,该微服务使用Feign调用上文的:8081/接口。

按照前文整合 Boot的步骤,在相同Realm中,创建一个新的,名为ms--,然后为ms--微服务也整合。下面我们使用Feign实现Token的传递:

只需编写一个Feign拦截器:

public class KeycloakRequestInterceptor implements RequestInterceptor {
    private static final String AUTHORIZATION_HEADER = "Authorization";
    @Override
    public void apply(RequestTemplate template) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Principal principal = attributes.getRequest().getUserPrincipal();
        if (principal != null && principal instanceof KeycloakPrincipal) {
            KeycloakSecurityContext keycloakSecurityContext = ((KeycloakPrincipal) principal)
                    .getKeycloakSecurityContext();
            if (keycloakSecurityContext instanceof RefreshableKeycloakSecurityContext) {
                RefreshableKeycloakSecurityContext.class.cast(keycloakSecurityContext)
                        .refreshExpiredToken(true);
                template.header(AUTHORIZATION_HEADER, "Bearer " + keycloakSecurityContext.getTokenString());
            }
        }
        // 否则啥都不干
    }
}

由该拦截器代码不难看出,我们把自己接收的Token,放到中,传递给服务提供者(即:ms--) 。

这样,我们就实现了ms--以及ms--两个微服务之间的Token传递——即:单点登录

使用Zuul传递Token

在 Cloud构建的应用中,往往使用Zuul作为对外服务的入口,架构图如下:

token 权限管理·(中国)官方网站_tokenrank官网_tokenpocet官网

此时,我们希望达到:在Zuul微服务上达到统一认证的效果——即:在Zuul上登录,就相当于登录了所有微服务。

要怎么办呢?这个问题,其实就是:Zuul信任的Token要如何传递给Zuul所代理的微服务呢?

我们创建一个新的,名为zuul-,然后编写一个Zuul过滤器:

@Component
public class KeycloakRouteZuulFilter extends ZuulFilter {
    private static final String AUTHORIZATION_HEADER = "Authorization";
    @Override
    public String filterType() {
        return FilterConstants.ROUTE_TYPE;
    }
    @Override
    public int filterOrder() {
        return 1;
    }
    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        Principal principal = request.getUserPrincipal();
        return principal != null && principal instanceof KeycloakPrincipal;
    }
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        if (ctx.getRequest().getHeader(AUTHORIZATION_HEADER) == null) {
            this.addKeycloakTokenToHeader(ctx);
        }
        return null;
    }
    private void addKeycloakTokenToHeader(RequestContext ctx) {
        Principal principal = ctx.getRequest()
                .getUserPrincipal();
        // 这里之所以可以直接强制转换,是因为shouldFilter中已经做了类型判断。
        KeycloakSecurityContext keycloakSecurityContext = ((KeycloakPrincipal) principal)
                .getKeycloakSecurityContext();
        if (keycloakSecurityContext instanceof RefreshableKeycloakSecurityContext) {
            ctx.addZuulRequestHeader(AUTHORIZATION_HEADER,
                    this.buildBearerToken(
                            (RefreshableKeycloakSecurityContext) keycloakSecurityContext
                    )
            );
        }
        // 用户没有登录,啥都不干
    }
    private String buildBearerToken(RefreshableKeycloakSecurityContext securityContext) {
        return "Bearer " + securityContext.getTokenString();
    }
}

由代码可知,我们在该过滤器中实现了Token的传递。

代码详见ms--

配置改进

上文,我们创建的都是 类型的,而现在,其实只有Zuul需要对外,其他服务都是经过Zuul或者Feign传递Token的。因此,我们可将除Zuul以外的所有的 Type统统改为-only,如图所示:

tokenrank官网_tokenpocet官网_token 权限管理·(中国)官方网站

代码详见zuul-。

登录相关配置

前文中,我们是自己添加用户的,现实中,用户往往是注册的;另外,如果我想实现 Me的功能该怎么办呢?难道这一切都需要自己编码吗?显然不需要!只需按需在下图中配置即可:

tokenpocet官网_token 权限管理·(中国)官方网站_tokenrank官网

例如,我们想实现用户注册token 权限管理·(中国)官方网站,只需将User 勾选即可。这样登录页面就会变成类似下图:

tokenpocet官网_token 权限管理·(中国)官方网站_tokenrank官网

主题定制

自带的届满稍微有那么一点丑陋,但允许我们自定义主题——

开发好主题后,将主题目录复制到$/目录中即可。默认为我们准备了两套主题,如下图:

tokenrank官网_tokenpocet官网_token 权限管理·(中国)官方网站

我们可参考这两套主题的代码,编写我们自己的主题。主题定制比较简单,是用搞的。万能上也有一些主题,只需要搜 theme 即可找到。个别主题还是不错的。

第三方认证

很多网站有QQ登录、登录、新浪微博登录等第三方认证按钮。如果我们也想实现第三方认证该怎么办呢?也具备这样的能力!下面笔者以登录为例,为我们的应用实现使用账号登录的能力!

在管理控制台上按下图操作:

tokenpocet官网_tokenrank官网_token 权限管理·(中国)官方网站

将会看到类似如下的界面,在这个页面上, ID以及 是必填项,如何获得这两项的值呢?

登录,访问//,点击左侧的 按钮,将会看到类似如下的界面:

tokenrank官网_tokenpocet官网_token 权限管理·(中国)官方网站

点击New OAuth App按钮,将会看到类似于如下的界面:

tokenrank官网_tokenpocet官网_token 权限管理·(中国)官方网站

点击 按钮后,即可看到该应用的 ID以及 。

回到管理控制台,填入获得的 ID以及 。

下面,我们来为用户分配角色。点击下图中的Edit按钮:

token 权限管理·(中国)官方网站_tokenpocet官网_tokenrank官网

将会看到类似如下的界面。点击右侧的:

tokenpocet官网_token 权限管理·(中国)官方网站_tokenrank官网

将会看到类似如下的界面。按照下图填写信息,其中Name随意,建议设置一个人类可读的名称即可。

tokenpocet官网_tokenrank官网_token 权限管理·(中国)官方网站

测试

注销后,重新访问任意一个需要登录的URL,将会看到类似如下的界面:

tokenrank官网_tokenpocet官网_token 权限管理·(中国)官方网站

由图可知,激动人心的登录按钮已经出现了。

访问zuul/ms--/,该地址需要user-role角色才能访问。如果可正常访问。说明配置成功。

术语

在继续之前,了解 引入的术语和概念非常重要。

(资源服务器)

根据术语, 是托管受保护资源并能够接受和响应受保护资源请求的服务器。

通常依靠某种信息来决定是否允许访问受保护的资源。对于基于的 ,该信息通常在 token中携带,通常作为 token,连同对服务器的每个请求一起发送。依靠会话来验证用户的Web应用程序通常将该信息存储在用户的会话中,并从那里为每个请求进行检索。

在中,任何 应用都可充当 。此的资源和各自的scope受到一组 的保护和管理。

(资源)

是应用和组织的资产的一部分。它可以是一组端点,一个经典的网页资源,如HTML页面等。在 术语中,资源是受保护的对象。

每个都有唯一的标识符,可用来表示单个或一组资源。例如,您可以管理一个 ,该会为所有银行账户定义一组 。但是,您也可拥有一个名为Alice’s 的资源,这个代表一个客户拥有的单一,它也可拥有自己的一组 。

Scope

的scope是可在上执行的有限的访问范围。在 术语中,scope是逻辑上可应用于的潜在的动词之一。

它通常表示对于给定的,能做些什么。scope的例子是查看、编辑、删除等。但是,scope也可与资源提供的特定信息相关。在这种情况下,您可以拥有 和cost scope,其中cost scope用于定义用户访问项目cost的特定策略和权限。

(权限)

想想这个简单和非常普遍的:

将受保护的对象与必须评估的关联起来,以确定是否授予访问权限。

X CAN DO Y ON RESOURCE Z
where …

提供了一个丰富的平台,用于构建从简单到非常复杂、基于规则的动态权限等一系列 。它提供了灵活性,并有助于:

(策略)

定义了授予访问对象必须满足的条件。与不同,您无需指定受保护的对象,而是指定访问给定对象(例如,、scope或两者)时必须满足的条件。与可用于保护资源的、不同的访问控制机制( :ACM)密切相关。通过,您可实施基于属性的访问控制(-based :ABAC),基于角色的访问控制(role-based :RBAC),基于上下文的访问控制(-based )或这些的任意组合的策略。

利用的概念,以及如何通过提供聚合的概念来定义它们,您可以在其中构建“ 中的 ”,并仍然控制评估的行为。 中的实施遵循分而治之的技术,而不是写出一个满足访问给定必须满足的所有条件的大型。也就是说,您可创建单独的,然后与不同的重用它们,并通过组合各个构建更复杂的。

(策略提供者)

是特定类型的实现。提供内置的,由相应的 支持,您可以创建自己的类型来支持您的特定需求。

提供了一个SPI( :服务提供者接口),您可以使用它来插入自己的策 实现。

(许可签名)

是由的用户管理访问(’s User- (UMA) :UMA)配置文件规范定义的一种特殊类型的token,它提供了一种由 确定的不透明结构。该结构表示客户请求的和/或scope,以及必须应用于授权数据请求(请求方令牌 party token:[RPT])的。

在UMA中, 对于支持人与人之间的共享以及人与组织之间的共享至关重要。为 使用 可实现从简单到复杂的一系列场景,其中 owner和 基于对这些访问的细粒度策略完全控制其资源。

在UMA 中imToken钱包官网, 向 发出 , 将 返回给试图访问受保护资源的。一旦收到,它就可通过将发送回 来请求RPT(持有数据的最后一个令牌)。

有关 的更多信息,请参阅 API和 UMA 规范。