java hipster!_通过Java Hipster升级Spring Security OAuth和JUnit测试
java hipster!
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
使用單元測試和集成測試來驗證代碼質量是一種很好的方式來表明您對代碼的關心。 最近,我在受歡迎的JHipster開源項目中做了很多工作,將其升級為使用最新版本的Spring Security。
Spring Security 5.1+將OAuth 2.0和OIDC添加為一流公民,您可以使用其優雅的DSL(又稱酷方法鏈接,又稱生成器模式)對其進行配置。 自從Rob Winch和工作人員首次啟動它以來,我一直有使用它的動力。 與他們合作進行非常創新的項目很有趣。 Spring Security使OAuth很棒!
我在2017年秋天向JHipster添加了OAuth 2.0支持。這種經歷對我產生了很大的影響。 我學到了很多有關Keycloak,Docker Compose以及如何在身份提供者(IdP)之間進行切換的知識。
我花了最后一個月升級JHipster以使用Spring Security 5.1(Spring Boot 2.1中的默認設置)。 在此過程中,我遇到了一些挫折,在Travis CI上搖了搖拳,當我想出解決方案時感到很高興。 在此過程中,我也學到了很多東西。 今天,我將與您分享這些經驗。
使用OAuth 2.0和OIDC注銷
在JHipster中集成了對Keycloak和Okta的支持后不久,該項目收到了很多用戶的抱怨,他們無法注銷。 JHipster用戶熟悉單擊注銷 (檢查最新信息)并完全注銷。 使用默認的Spring Security支持,用戶將注銷本地應用程序,而不是IdP。
我花了一年的時間,但終于在今年早些時候添加了全球SSO注銷 。 Keycloak和Okta都要求您將GET請求發送到具有ID令牌和要重定向到的URL的端點。 因此,我創建了一個LogoutResource來返回這些值。
@RestController public class LogoutResource {private final Logger log = LoggerFactory.getLogger(LogoutResource.class);private final UserInfoRestTemplateFactory templateFactory;private final String accessTokenUri;public LogoutResource(UserInfoRestTemplateFactory templateFactory,@Value("${security.oauth2.client.access-token-uri}") String accessTokenUri) {this.templateFactory = templateFactory;this.accessTokenUri = accessTokenUri;}/*** POST /api/logout : logout the current user** @return the ResponseEntity with status 200 (OK) and a body with a global logout URL and ID token*/@PostMapping("/api/logout")public ResponseEntity<?> logout(HttpServletRequest request, Authentication authentication) {log.debug("REST request to logout User : {}", authentication);OAuth2RestTemplate oauth2RestTemplate = this.templateFactory.getUserInfoRestTemplate();String idToken = (String) oauth2RestTemplate.getAccessToken().getAdditionalInformation().get("id_token");String logoutUrl = accessTokenUri.replace("token", "logout");Map<String, String> logoutDetails = new HashMap<>();logoutDetails.put("logoutUrl", logoutUrl);logoutDetails.put("idToken", idToken);request.getSession().invalidate();return ResponseEntity.ok().body(logoutDetails);} }Angular客戶端調用/api/logout端點并構造IdP注銷URL。
this.authServerProvider.logout().subscribe(response => {const data = response.body;let logoutUrl = data.logoutUrl;// if Keycloak, uri has protocol/openid-connect/tokenif (logoutUrl.indexOf('/protocol') > -1) {logoutUrl = logoutUrl + '?redirect_uri=' + window.location.origin;} else {// OktalogoutUrl = logoutUrl + '?id_token_hint=' +data.idToken + '&post_logout_redirect_uri=' + window.location.origin;}window.location.href = logoutUrl; });測試LogoutResource非常簡單。 大部分工作涉及模擬UserInfoRestTemplateFactory以便它返回ID令牌。
@RunWith(SpringRunner.class) @SpringBootTest(classes = JhipsterApp.class) public class LogoutResourceIntTest {@Autowiredprivate MappingJackson2HttpMessageConverter jacksonMessageConverter;private final static String ID_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" +".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm" +"p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M" +"Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr" +"oqqUrg";@Value("${security.oauth2.client.access-token-uri}")private String accessTokenUri;private MockMvc restLogoutMockMvc;@Beforepublic void before() {LogoutResource logoutResource = new LogoutResource(restTemplateFactory(), accessTokenUri);this.restLogoutMockMvc = MockMvcBuilders.standaloneSetup(logoutResource).setMessageConverters(jacksonMessageConverter).build();}@Testpublic void getLogoutInformation() throws Exception {String logoutUrl = accessTokenUri.replace("token", "logout");restLogoutMockMvc.perform(post("/api/logout")).andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)).andExpect(jsonPath("$.logoutUrl").value(logoutUrl)).andExpect(jsonPath("$.idToken").value(ID_TOKEN));}private UserInfoRestTemplateFactory restTemplateFactory() {UserInfoRestTemplateFactory factory = mock(UserInfoRestTemplateFactory.class);Map<String, Object> idToken = new HashMap<>();idToken.put("id_token", ID_TOKEN);DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("my-fun-token");token.setAdditionalInformation(idToken);when(factory.getUserInfoRestTemplate()).thenReturn(mock(OAuth2RestTemplate.class));when(factory.getUserInfoRestTemplate().getAccessToken()).thenReturn(token);return factory;} }我在1月下旬將全局注銷支持合并到JHipster的master分支中,并在幾周后開始升級Spring Security的OIDC支持。
升級Spring Security的OIDC支持
我從創建問題#9276開始,以跟蹤我的目標,動機和已知問題。
在這一點上,如果您不熟悉Spring Security,您可能想知道:為什么升級到Spring Security的最新版本如此酷? 長話短說:它們已經棄用了注釋,增加了功能,并使將OAuth 2.0和OIDC集成到您的應用程序中變得更加容易。 謝謝,Spring Security團隊!
在Spring Boot 2.1+(即Spring Security 5.1+)中,不再建議使用@ EnableOAuth2Sso和@EnableResourceServer。 更改的原因可以在2019年1月25日發布的Josh Long的Bootiful Podcast中找到。這是Madhura Bhave的訪談,討論從21:30開始。
除了將所有Java代碼和YAML配置轉換為使用最新的Spring Security比特外,我還決定默認情況下將每個JHipster應用程序配置為資源服務器。 這是JHipster的SecurityConfiguration.java.ejs模板中的邏輯:
@Override public void configure(HttpSecurity http) throws Exception {// @formatter:offhttp...<%_ } else if (authenticationType === 'oauth2') { _%><%_ if (['monolith', 'gateway'].includes(applicationType)) { _%>.and().oauth2Login()<%_ } _%>.and().oauth2ResourceServer().jwt();<%_ } _%>// @formatter:on} }為了確保實現與OIDC兼容,我用進行觀眾驗證的JwtDecoder bean覆蓋了默認的JwtDecoder bean。
@Value("${spring.security.oauth2.client.provider.oidc.issuer-uri}") private String issuerUri;@Bean JwtDecoder jwtDecoder() {NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport)JwtDecoders.fromOidcIssuerLocation(issuerUri);OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator();OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);jwtDecoder.setJwtValidator(withAudience);return jwtDecoder; }在所有運行時代碼正常工作之后,我開始進行重構測試。 測試是重構成功的最可靠指標,尤其是對于像JHipster這樣具有26,000個組合的項目而言!
在此過程中,我遇到了許多挑戰。 由于我學到了很多解決這些挑戰的知識,所以我認為對它們進行說明以及如何解決它們很有趣。
如何模擬具有ID令牌的AuthenticatedPrincipal
我遇到的第一個挑戰是更新的LogoutResource 。 下面是將其重構為使用Spring Security的ClientRegistrationRepository之后的代碼。
@RestController public class LogoutResource {private ClientRegistration registration;public LogoutResource(ClientRegistrationRepository registrations) {this.registration = registrations.findByRegistrationId("oidc");}/*** {@code POST /api/logout} : logout the current user.** @param request the {@link HttpServletRequest}.* @param idToken the ID token.* @return the {@link ResponseEntity} with status {@code 200 (OK)} and a body with a global logout URL and ID token.*/@PostMapping("/api/logout")public ResponseEntity<?> logout(HttpServletRequest request,@AuthenticationPrincipal(expression = "idToken") OidcIdToken idToken) {String logoutUrl = this.registration.getProviderDetails().getConfigurationMetadata().get("end_session_endpoint").toString();Map<String, String> logoutDetails = new HashMap<>();logoutDetails.put("logoutUrl", logoutUrl);logoutDetails.put("idToken", idToken.getTokenValue());request.getSession().invalidate();return ResponseEntity.ok().body(logoutDetails);} }我試圖在LogoutResourceIT.java模擬OAuth2AuthenticationToken ,以為這將導致AuthenticationPrincipal的填充。
@RunWith(SpringRunner.class) @SpringBootTest(classes = JhipsterApp.class) public class LogoutResourceIT {@Autowiredprivate ClientRegistrationRepository registrations;@Autowiredprivate MappingJackson2HttpMessageConverter jacksonMessageConverter;private final static String ID_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" +".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm" +"p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M" +"Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr" +"oqqUrg";private MockMvc restLogoutMockMvc;@Beforepublic void before() {LogoutResource logoutResource = new LogoutResource(registrations);this.restLogoutMockMvc = MockMvcBuilders.standaloneSetup(logoutResource).setMessageConverters(jacksonMessageConverter).build();}@Testpublic void getLogoutInformation() throws Exception {Map<String, Object> claims = new HashMap<>();claims.put("groups", "ROLE_USER");claims.put("sub", 123);OidcIdToken idToken = new OidcIdToken(ID_TOKEN, Instant.now(),Instant.now().plusSeconds(60), claims);String logoutUrl = this.registrations.findByRegistrationId("oidc").getProviderDetails().getConfigurationMetadata().get("end_session_endpoint").toString();restLogoutMockMvc.perform(post("/api/logout").with(authentication(createMockOAuth2AuthenticationToken(idToken)))).andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)).andExpect(jsonPath("$.logoutUrl").value(logoutUrl));}private OAuth2AuthenticationToken createMockOAuth2AuthenticationToken(OidcIdToken idToken) {Collection<GrantedAuthority> authorities = new ArrayList<>();authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER));OidcUser user = new DefaultOidcUser(authorities, idToken);return new OAuth2AuthenticationToken(user, authorities, "oidc");} }但是,這導致以下錯誤:
Caused by: java.lang.IllegalArgumentException: tokenValue cannot be emptyat org.springframework.util.Assert.hasText(Assert.java:284)at org.springframework.security.oauth2.core.AbstractOAuth2Token.<init>(AbstractOAuth2Token.java:55)at org.springframework.security.oauth2.core.oidc.OidcIdToken.<init>(OidcIdToken.java:53)at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:172)我將這個問題發布到Stack Overflow上,并且還向Spring Security團隊發送了電子郵件。 Joe Grandja對此問題做出了回應。
AuthenticationPrincipalArgumentResolver未在您的測試中注冊。
啟用“完整” spring-web-mvc時,它將自動注冊,例如@EnableWebMvc 。
但是,在您的@Before ,您具有:
MockMvcBuilders.standaloneSetup() –這不會初始化完整的web-mvc基礎結構–只是一個子集。
嘗試以下方法:
MockMvcBuilders.webAppContextSetup(this.context) –這將注冊AuthenticationPrincipalArgumentResolver并且您的測試應解析OidcIdToken 。
喬是正確的。 我將測試更改為以下內容,并通過了測試。 ?
@RunWith(SpringRunner.class) @SpringBootTest(classes = JhipsterApp.class) public class LogoutResourceIT {@Autowiredprivate ClientRegistrationRepository registrations;@Autowiredprivate WebApplicationContext context;private final static String ID_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" +".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm" +"p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M" +"Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr" +"oqqUrg";private MockMvc restLogoutMockMvc;@Beforepublic void before() throws Exception {Map<String, Object> claims = new HashMap<>();claims.put("groups", "ROLE_USER");claims.put("sub", 123);OidcIdToken idToken = new OidcIdToken(ID_TOKEN, Instant.now(),Instant.now().plusSeconds(60), claims);SecurityContextHolder.getContext().setAuthentication(authenticationToken(idToken));SecurityContextHolderAwareRequestFilter authInjector = new SecurityContextHolderAwareRequestFilter();authInjector.afterPropertiesSet();this.restLogoutMockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();}@Testpublic void getLogoutInformation() throws Exception {String logoutUrl = this.registrations.findByRegistrationId("oidc").getProviderDetails().getConfigurationMetadata().get("end_session_endpoint").toString();restLogoutMockMvc.perform(post("/api/logout")).andExpect(status().isOk()).andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)).andExpect(jsonPath("$.logoutUrl").value(logoutUrl)).andExpect(jsonPath("$.idToken").value(ID_TOKEN));}private OAuth2AuthenticationToken authenticationToken(OidcIdToken idToken) {Collection<GrantedAuthority> authorities = new ArrayList<>();authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER));OidcUser user = new DefaultOidcUser(authorities, idToken);return new OAuth2AuthenticationToken(user, authorities, "oidc");} }正確測試注銷功能是一個重要的里程碑。 我繼續升級JHipster的微服務架構。
如何使用Zuul將OAuth 2.0訪問令牌傳遞給下游微服務
JHipster使用Netflix Zuul代理從網關到下游微服務的請求。 我創建了一個AuthorizationHeaderFilter來處理訪問令牌傳播。
public class AuthorizationHeaderFilter extends ZuulFilter {private final AuthorizationHeaderUtil headerUtil;public AuthorizationHeaderFilter(AuthorizationHeaderUtil headerUtil) {this.headerUtil = headerUtil;}@Overridepublic String filterType() {return PRE_TYPE;}@Overridepublic int filterOrder() {return Ordered.LOWEST_PRECEDENCE;}@Overridepublic boolean shouldFilter() {return true;}@Overridepublic Object run() {RequestContext ctx = RequestContext.getCurrentContext();Optional<String> authorizationHeader = headerUtil.getAuthorizationHeader();authorizationHeader.ifPresent(s -> ctx.addZuulRequestHeader(TokenRelayRequestInterceptor.AUTHORIZATION, s));return null;} }但是,添加它不會導致成功訪問令牌傳播。 在Jon Ruddell的幫助下 ,我發現這是因為JHipster有一個LazyInitBeanFactoryPostProcessor導致所有bean都被延遲加載。 該ZuulFilterInitializer中包含ZuulFilterInitializer 。 將ZuulFilterInitializer為熱切加載的bean,可以使一切正常工作。
至此,我一切正常,因此創建了一個pull請求來升級JHipster的模板 。
我知道我簽入的內容需要運行Keycloak才能通過集成測試。 這是由于OIDC發現以及如何從.well-known/openid-configuration查找端點。
在Spring Boot集成測試中如何處理OIDC發現
我不太擔心Keycloak是否需要運行才能通過集成測試。 然后,我們的某些Azure和Travis構建開始失敗。 JHipster開發人員指出,當Keycloak不運行時,他們會看到類似以下的錯誤。
Factory method 'clientRegistrationRepository' threw exception; nested exception is java.lang.IllegalArgumentException: Unable to resolve the OpenID Configuration with the provided Issuer of "http://localhost:9080/auth/realms/jhipster"我通過Spring Security的OAuth和OIDC測試進行了一些摸索,并提出了一個解決方案 。 該修復程序涉及添加一個TestSecurityConfiguration類,該類將覆蓋默認的Spring Security設置并模擬Bean,從而不會發生OIDC發現。
@TestConfiguration public class TestSecurityConfiguration {private final ClientRegistration clientRegistration;public TestSecurityConfiguration() {this.clientRegistration = clientRegistration().build();}@BeanClientRegistrationRepository clientRegistrationRepository() {return new InMemoryClientRegistrationRepository(clientRegistration);}private ClientRegistration.Builder clientRegistration() {Map<String, Object> metadata = new HashMap<>();metadata.put("end_session_endpoint", "https://jhipster.org/logout");return ClientRegistration.withRegistrationId("oidc").redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}").clientAuthenticationMethod(ClientAuthenticationMethod.BASIC).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).scope("read:user").authorizationUri("https://jhipster.org/login/oauth/authorize").tokenUri("https://jhipster.org/login/oauth/access_token").jwkSetUri("https://jhipster.org/oauth/jwk").userInfoUri("https://api.jhipster.org/user").providerConfigurationMetadata(metadata).userNameAttributeName("id").clientName("Client Name").clientId("client-id").clientSecret("client-secret");}@BeanJwtDecoder jwtDecoder() {return mock(JwtDecoder.class);}@Beanpublic OAuth2AuthorizedClientService authorizedClientService(ClientRegistrationRepository clientRegistrationRepository) {return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);}@Beanpublic OAuth2AuthorizedClientRepository authorizedClientRepository(OAuth2AuthorizedClientService authorizedClientService) {return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);} }然后,在使用@SpringBootTest類中,我將其配置為配置源。
@SpringBootTest(classes = {MicroApp.class, TestSecurityConfiguration.class})在使用OAuth 2.0保護的JHipster微服務上運行端到端測試
最終問題很快就浮出水面了。 jhipster-daily-build (在Azure DevOps上運行)在嘗試測試微服務時失敗。
Caused by: java.lang.IllegalArgumentException: Unable to resolve the OpenID Configurationwith the provided Issuer of "http://localhost:9080/auth/realms/jhipster"我們不包括用于微服務的Keycloak Docker Compose文件,因為我們不希望它們獨立運行。 他們需要網關才能訪問它們,因此其OAuth 2.0設置應與您的網關匹配,并且網關項目中包含Keycloak文件。
在Azure上運行的端到端測試,其中1)啟動微服務,2)達到其運行狀況終結點以確保其成功啟動。 為了解決此問題, Pascal Grimaud 禁用了啟動/測試微服務 。 他還創建了一個新問題來改進流程,因此可以使用JHipster的JDL生成完整的微服務堆棧。
升級到Spring Security 5.1及其一流的OIDC支持
我希望這些挑戰和修復方法列表對您有所幫助。 如果您使用不推薦使用的@EnableOAuth2Sso或@EnableResourceServer ,我建議您嘗試升級到Spring Security 5.1。 我用來跟蹤升級的問題包含顯示所有必需的代碼更改的鏈接。
- 整體所需的代碼更改
- 微服務架構所需的代碼更改
使用JHipster 6生成帶有OIDC進行身份驗證的Spring Boot + React應用
JHipster 6使用最新和最好的Spring Boot和Spring Security版本。 它的前端支持Angular和React。 它也支持Vue ,它不是主要生成器的一部分。
如果使用JHipster 6生成應用程序,則本文中提到的所有測試功能都將包含在您的應用程序中。 你是怎樣做的? 我很高興你問!
首先安裝JHipster 6 Beta:
npm命令是Node.js的一部分。 您將需要Node 10.x來安裝JHipster并運行有用的命令。
JHipster 6支持Java 8、11和12(感謝Spring Boot 2.1)。 我建議使用SDKMAN管理Java SDK ! 例如,您可以安裝Java 12并將其設置為默認值。
sdk install java 12.0.0-open sdk default java 12.0.0-open您可以創建一個使用React和OIDC的JHipster應用,只需幾個命令:
mkdir app && cd appecho "application { config { baseName reactoidc, \authenticationType oauth2, clientFramework react } }" >> app.jhjhipster import-jdl app.jh下面是顯示這些命令結果的終端記錄。
必須已配置的OIDC提供程序正在運行,JHipster生成的Spring Boot應用程序才能成功啟動。 您可以使用Docker Compose啟動Keycloak:
docker-compose -f src/main/docker/keycloak.yml up -d然后使用Maven啟動您的應用程序:
./mvnw啟動完成后,打開http://localhost:8080 ,然后單擊登錄 。 您將被重定向到Keycloak,您可以在其中輸入admin/admin登錄。
為什么用Okta代替Keycloak?
Keycloak的效果很好,但這是Okta開發人員博客上的文章,所以讓我向您展示如何使用Okta! 為什么要使用Okta? 這是一個很好的問題。
Okta是永遠在線的身份提供者,為開發人員提供身份驗證和授權服務。 它還允許您管理用戶。 我喜歡將其稱為“用戶作為軟件服務”,但UASS并不是一個很好的縮寫。 用戶管理作為軟件服務(UMASS)可以輕松解決。 無論如何,這是一項很棒的服務,您應該嘗試一下。
注冊您的安全Spring Boot應用程序
首先,注冊一個免費的Okta開發人員帳戶 (如果已經有一個帳戶,則登錄)。
登錄Okta后,注冊您的Spring Boot應用程序。
- 在頂部菜單中,單擊“ 應用程序”
- 點擊添加應用
- 選擇網站 ,然后單擊下一步。
- 輸入名字
- 將登錄重定向URI更改為http://localhost:8080/login/oauth2/code/oidc
- 點擊完成 ,然后點擊編輯 ,然后添加http://localhost:8080作為注銷重定向URI。
- 點擊保存
完成后,您的設置應類似于以下屏幕截圖。
在項目的根目錄中創建okta.env文件,并將{..}值替換為Okta應用程序中的值:
export SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI=https://{yourOktaDomain}/oauth2/default export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID={clientId} export SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET={clientSecret}在您的.gitignore文件中添加*.env ,這樣該文件就不會在GitHub上結束。
創建組并將其作為聲明添加到ID令牌
默認情況下,JHipster配置為與兩種類型的用戶一起使用:管理員和用戶。 Keycloak會自動為用戶和組配置,但是您需要為Okta組織進行一次一次性配置。
創建一個ROLE_ADMIN和ROLE_USER組(“ 用戶” >“ 組” >“ 添加組” )并將用戶添加到其中。 您可以使用注冊時使用的帳戶,也可以創建一個新用戶(“ 用戶” >“ 添加人” )。 導航到API > 授權服務器 ,然后單擊default服務器。 點擊索賠標簽,然后添加索賠 。 將其命名為groups ,并將其包含在ID令牌中。 將值類型設置為Groups并將過濾器設置為.*的正則表達式。 點擊創建 。
使用以下命令啟動您的應用程序:
source okta.env ./mvnw導航到http://localhost:8080并使用Okta憑據登錄。
漂亮的臀部,你不覺得嗎? 🤓
使用JHipster進行更好的Java測試
JHipster為您生成了一個具有開箱即用的良好測試覆蓋范圍的應用程序。 使用自動為您配置的SonarCloud分析代碼覆蓋率。 運行以下命令以在Docker容器中啟動Sonar。
docker-compose -f src/main/docker/sonar.yml up -d然后運行以下Maven命令:
./mvnw -Pprod clean test sonar:sonar -Dsonar.host.url=http://localhost:9001該過程完成后,導航至http://localhost:9001/projects ,您將看到項目的報告。
代碼覆蓋率比本報告中顯示的要高得多。 我們最近更改了許多測試以在集成測試階段運行,并且還沒有弄清楚如何將此數據報告給Sonar。
有關此功能的更多信息,請參見JHipster的代碼質量文檔 。
對JHipster中的JUnit 5的支持也在進行中 。
了解有關Spring Security,Spring Boot和JHipster的更多信息
我希望您喜歡我有關升級JHipster以使用Spring Security 5.1及其出色的OAuth 2.0 + OIDC支持的故事。 我真的很喜歡Spring Security團隊所做的工作,以簡化其配置并使OIDC發現(以及其他功能)正常工作。
由于JHipster生成了所有代碼,因此我沒有為該示例創建GitHub存儲庫,因此不需要修改任何內容。
如果您想了解有關JHipster 6的更多信息,請參閱Java 12和JHipster 6更好,更快,更輕便的Java 。 如果您對JHipster的CRUD生成功能和PWA支持感興趣,我鼓勵您閱讀我的博客文章, 了解如何使用React,Spring Boot和JHipster構建照相館PWA 。
我們還發布了許多有關測試和Spring Security 5.1的文章:
- 使用JUnit 5測試您的Spring Boot應用程序
- 使用WireMock,Jest,Protractor和Travis CI測試Spring Boot API和Angular組件的Hitchhiker指南
- 帶有Spring Security的OAuth 2.0快速指南
- 將您的Spring Boot應用程序遷移到最新和最新的Spring Security和OAuth 2.0
需要更多技術提示嗎? 在社交網絡{ Twitter , LinkedIn , Facebook , YouTube }上關注我們,以便在我們發布新內容時得到通知。
是否有與Okta無關的問題? 請在我們的開發人員論壇上提問。
“通過Java Hipster升級Spring Security OAuth和JUnit測試”最初于2019年4月15日發布在Okta開發人員博客上。
“我喜歡編寫身份驗證和授權代碼。” ?從來沒有Java開發人員。 厭倦了一次又一次地建立相同的登錄屏幕? 嘗試使用Okta API進行托管身份驗證,授權和多因素身份驗證。
翻譯自: https://www.javacodegeeks.com/2019/05/spring-security-oauth-through-java-hipster.html
java hipster!
總結
以上是生活随笔為你收集整理的java hipster!_通过Java Hipster升级Spring Security OAuth和JUnit测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sap wad_使用网真和WAD热部署K
- 下一篇: 张大仙后羿出装及铭文(张大仙后羿出装及铭