keyclock单点登陆 --- springboot+springsecurity+keycloak整合

参考文章:keyclock单点登陆  

springboot+springsecurity+keycloak整合

认识JWT

原理简介

Users

是一种可以登录系统的实体,可以拥有一些属性,如email、username、address、phone number等,

可以加入组,成为组成员

可以分配角色

Authentication

识别和验证用户

Authorization

为用户授权

Credentials

Keycloak用来识别和验证用户的一些数据,如密码、一次性密码、数字签名、指纹。

Roles

角色,用户的一个分类,如管理员、普通用户、管理者、普通雇员等

应用程序一般会将权限分配给指定角色,而不是直接分配给用户。

角色分为Realm级别角色和client级别角色。

用户可以同时拥有Realm角色和不同client的client级别的角色。

User role mapping

一个用户可以与0个或多个角色关联,这些关联关系可以被包含进token或assertions中,applications可以根据这些映射关系来进行访问控制。

Composite roles 复合角色

一个复合角色可以关联多个普通角色,如复合角色superuser可以关联sales-admin、order-entry-admin角色,如果用户拥有superuser角色,则相当于同时拥有sales-admin和order-entry-admin角色。

Groups

组是为了更方便的管理用户

可以为组定义属性

可以为组分配角色

组成员自动继承组的属性和角色。

Realm 领域

一个realm管理一系列user、Credentials、roles、groups。

一个user隶属于一个realm

一个user也只能log in 一个realm

Realm彼此之间是隔离的

每个realm只能管理和认证自己控制的user

Clients

Clients可以请求keycloak去认证一个user

大多数情况下,clients是一些应用和服务,这些application和service想要通过keycloak加固自己,并提供单点登录解决方案。

Clients还可以仅仅请求认证信息或者访问token,这样他们可以安全的调用其他被keycloak保护的服务。

Client apapters

Client适配器 是一种插件,

这种插件是用来安装在你的应用环境上的,

安装后,可以与keycloak进行通信,并被keycloak保护。

Keycloak针对不同的应用环境提供了不同的适配器,可以下载。

 有些应用环境keycloak没有提供apapter,可以使用第三方开发的adapter。

-------------------------------------------------------------

springboot+springsecurity+keycloak整合

1、在keycloak中配置client

keycloak管理界面点击client,创建client,填写clientID

有效的重定向URI配置指向工单系统的UI首页地址

启用隐式流

web起源设为 *

2、加入keycloak依赖和json文件

pom.xml


4.4.0.Final

    org.keycloak
    keycloak-spring-security-adapter
    ${keycloak.version}


    org.keycloak
    keycloak-spring-boot-starter
    ${keycloak.version}

keycloak.json文件,放在resources目录下

{
  "realm": "realm",
  "auth-server-url": "http://xxx.xxx:8180/auth",
  "ssl-required": "external",
  "resource": "myclient",
  "public-client": true,
  "confidential-port": 0
}

application.properties文件

#keycloak
keycloak.realm=realm
keycloak.resource=myclient
keycloak.auth-server-url=http://xxx.xxx.xxx.xxx:8180/auth
keycloak.ssl-required=external

3、添加springsecurity+keycloak配置文件

不废话,直接上代码

@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
    @Autowired
    private SecurityAuthenticationProvider authenticationProvider;

    @Autowired
    private KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter;

    @Autowired
    private KeycloakPreAuthActionsFilter keycloakPreAuthActionsFilter;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    @Bean
    public KeycloakConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(
            KeycloakAuthenticationProcessingFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(true);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(
            KeycloakPreAuthActionsFilter filter) {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
        registrationBean.setEnabled(true);
        return registrationBean;
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new NullAuthenticatedSessionStrategy();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable()
                .cors().and()
                .sessionManagement().disable()
                .authorizeRequests()
                .anyRequest().permitAll();
        http
         //.addFilterBefore(mySecurityInterceptor, FilterSecurityInterceptor.class)
         .addFilterBefore(keycloakAuthenticationProcessingFilter, FilterSecurityInterceptor.class)
         .addFilterBefore(keycloakPreAuthActionsFilter, KeycloakAuthenticationProcessingFilter.class);
    }
}

4、自定义AuthenticationProvider

通过AccessToken中的用户信息,查询本系统中该用户的权限信息,加入token,具体鉴权方案各系统各不相同,自行实现

@Slf4j
@Component
public class SecurityAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;

    private GrantedAuthoritiesMapper grantedAuthoritiesMapper;

    public void setGrantedAuthoritiesMapper(GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
        this.grantedAuthoritiesMapper = grantedAuthoritiesMapper;
    }

    /**
     * 验证Authentication,建立系统使用者信息principal(token)
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws RuntimeException {
        //从token中获取用户信息
        KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) authentication;
        AccessToken accessToken = getAccessToken((token));
        String userId = accessToken.getSubject();
        //查询用户是否存在,若不存在则存入数据库
        userService.checkUser(accessToken, userId);
        //根据userId查询本系统用户权限,放入token中
        List grantedAuthorities = roleService.getGrantedAuthorities(userId);
        KeycloakAuthenticationToken authenticationToken = 
                        new KeycloakAuthenticationToken(token.getAccount(), 
                            token.isInteractive(), mapAuthorities(grantedAuthorities));
       
         return authenticationToken;
    }

    private AccessToken getAccessToken(KeycloakAuthenticationToken principal) {
        KeycloakAuthenticationToken token = principal;
        KeycloakPrincipal keycloakPrincipal = (KeycloakPrincipal)token.getPrincipal();
        KeycloakSecurityContext context = keycloakPrincipal.getKeycloakSecurityContext();
        return context.getToken();
    }

    private Collection mapAuthorities(
            Collection authorities) {
        return grantedAuthoritiesMapper != null
                ? grantedAuthoritiesMapper.mapAuthorities(authorities)
                : authorities;
    }

    @Override
    public boolean supports(Class aClass) {
        return KeycloakAuthenticationToken.class.isAssignableFrom(aClass);
    }
}

 

 

你可能感兴趣的:(keycloak,spring,security)