https://www.jianshu.com/p/efd32ace20dc
前言
登陆是一个项目的基础,几乎任何项目都需要包括登陆模块,网上大部分登陆都是使用的shrio,个人感觉这种东西很老,而且不好用,偶然之前发现了一个叫keycloak的sso开源项目, 感觉挺不错的,这篇文章主要讲解如何使用springboot和keycloak进行结合。
版本
- springboot: 1.4.3.RELEASE 版本
- keycloak: 2.5.1.Final 版本
- vue: 2.1.0 版本
项目搭建
- 首先搭建keycloak的服务 (略)
- 编写前端代码(用vue2写的简单的一个spa,略)
- 编写springboot的服务(略)
- 加入核心依赖
1 2 3 4 5 6 7 8 9 10 |
<span class="hljs-tag"><<span class="hljs-name">dependency</span>></span> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.keycloak<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>keycloak-tomcat8-adapter<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span> <span class="hljs-tag"><<span class="hljs-name">dependency</span>></span> <span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.keycloak<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span> <span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>keycloak-spring-security-adapter<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span> <span class="hljs-tag"></<span class="hljs-name">dependency</span>></span> |
- 在springboot的配置文件中加入
1 2 3 |
keycloak: configurationFile: <span class="hljs-string">"classpath:keycloak.json"</span> |
- 在resources的目录下加入
keycloak.json
配置文件
1 2 3 4 5 6 7 8 9 |
{ <span class="hljs-attr">"realm"</span>: <span class="hljs-string">"family"</span>, <span class="hljs-attr">"bearer-only"</span>: <span class="hljs-literal">true</span>, <span class="hljs-attr">"auth-server-url"</span>: <span class="hljs-string">"http://localhost:8080/auth"</span>, <span class="hljs-attr">"ssl-required"</span>: <span class="hljs-string">"external"</span>, <span class="hljs-attr">"resource"</span>: <span class="hljs-string">"family-app"</span>, <span class="hljs-attr">"enable-cors"</span>: <span class="hljs-literal">true</span> } |
- 配置springmvc的跨域filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<span class="hljs-meta">@Configuration</span> <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CorsFilterConfig</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> </span>{ <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span><span class="hljs-params">(FilterConfig filterConfig)</span> <span class="hljs-keyword">throws</span> ServletException </span>{} <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilter</span><span class="hljs-params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> <span class="hljs-keyword">throws</span> IOException, ServletException </span>{ HttpServletResponse res = (HttpServletResponse) servletResponse; res.setHeader(<span class="hljs-string">"Access-Control-Allow-Origin"</span>, <span class="hljs-string">"*"</span>); res.setHeader(<span class="hljs-string">"Access-Control-Allow-Methods"</span>, <span class="hljs-string">"POST, GET, OPTIONS, DELETE, PUT"</span>); res.setHeader(<span class="hljs-string">"Access-Control-Max-Age"</span>, <span class="hljs-string">"1728000"</span>); res.setHeader(<span class="hljs-string">"Access-Control-Allow-Headers"</span>, <span class="hljs-string">"Authorization, Content-Type, Accept, x-requested-with, Cache-Control"</span>); filterChain.doFilter(servletRequest, res); } <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">destroy</span><span class="hljs-params">()</span> </span>{} } |
- 配置keycloak和spring security结合的配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
<span class="hljs-meta">@Configuration</span> <span class="hljs-meta">@EnableWebSecurity</span> <span class="hljs-meta">@EnableGlobalMethodSecurity</span>(prePostEnabled = <span class="hljs-keyword">true</span>) <span class="hljs-meta">@ComponentScan</span>(basePackageClasses = KeycloakSecurityComponents.class) <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">KeycloakSecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">KeycloakWebSecurityConfigurerAdapter</span> </span>{ <span class="hljs-meta">@Autowired</span> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configureGlobal</span><span class="hljs-params">(AuthenticationManagerBuilder auth)</span> <span class="hljs-keyword">throws</span> Exception </span>{ auth.authenticationProvider(keycloakAuthenticationProvider()); } <span class="hljs-meta">@Bean</span> <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">protected</span> SessionAuthenticationStrategy <span class="hljs-title">sessionAuthenticationStrategy</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> NullAuthenticatedSessionStrategy(); } <span class="hljs-meta">@Bean</span> <span class="hljs-function"><span class="hljs-keyword">public</span> FilterRegistrationBean <span class="hljs-title">keycloakAuthenticationProcessingFilterRegistrationBean</span><span class="hljs-params">( KeycloakAuthenticationProcessingFilter filter)</span> </span>{ FilterRegistrationBean registrationBean = <span class="hljs-keyword">new</span> FilterRegistrationBean(filter); registrationBean.setEnabled(<span class="hljs-keyword">false</span>); <span class="hljs-keyword">return</span> registrationBean; } <span class="hljs-meta">@Bean</span> <span class="hljs-function"><span class="hljs-keyword">public</span> FilterRegistrationBean <span class="hljs-title">keycloakPreAuthActionsFilterRegistrationBean</span><span class="hljs-params">( KeycloakPreAuthActionsFilter filter)</span> </span>{ FilterRegistrationBean registrationBean = <span class="hljs-keyword">new</span> FilterRegistrationBean(filter); registrationBean.setEnabled(<span class="hljs-keyword">false</span>); <span class="hljs-keyword">return</span> registrationBean; } <span class="hljs-meta">@Override</span> <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{ <span class="hljs-keyword">super</span>.configure(http); http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .sessionAuthenticationStrategy(sessionAuthenticationStrategy()).and() .addFilterBefore(keycloakPreAuthActionsFilter(), LogoutFilter.class) .addFilterBefore(keycloakAuthenticationProcessingFilter(), X509AuthenticationFilter.class) .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint()).and() .authorizeRequests() .requestMatchers(CorsUtils::isCorsRequest).permitAll() <span class="hljs-comment">// .antMatchers("/family/*").hasAnyAuthority("user").antMatchers("/admin/*").hasRole("ADMIN")</span> .antMatchers(<span class="hljs-string">"/**"</span>).authenticated() .anyRequest().permitAll(); } } |
- 对应的接口上增加可以执行的用户角色
1 2 3 4 5 6 7 |
<span class="hljs-meta">@RequestMapping</span>(value = <span class="hljs-string">"/all"</span>, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) <span class="hljs-meta">@ResponseBody</span> <span class="hljs-meta">@PreAuthorize</span>(<span class="hljs-string">"hasAnyAuthority('user')"</span>) <span class="hljs-function"><span class="hljs-keyword">public</span> List<Family> <span class="hljs-title">queryAllFamilyInfo</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> familyInfoService.queryAllFamilyInfo(); } |
遇到的坑
- 对应keycloak的用户权限需要使用
hasAnyAuthority
而不是hasAnyRole
,并且需要在KeycloakSecurityConfig
类中加入@EnableGlobalMethodSecurity(prePostEnabled = true)
注解 keycloak-spring-security-adapter
和spring-boot-adpater
两个依赖不能同时使用- cors的跨域的配置,需要
CorsFilterConfig
的filter类配合KeycloakSecurityConfig
类中的requestMatchers(CorsUtils::isCorsRequest).permitAll()
一起使用
完整的项目地址(包括了简单的前端和后端代码,不会写前端,前端代码比较垃圾。。 需要完善 ):
作者:LOC_Thomas
链接:https://www.jianshu.com/p/efd32ace20dc
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。