diff --git a/pigx-common/pigx-common-bom/pom.xml b/pigx-common/pigx-common-bom/pom.xml index 5f547d631..41e482c1d 100644 --- a/pigx-common/pigx-common-bom/pom.xml +++ b/pigx-common/pigx-common-bom/pom.xml @@ -106,6 +106,11 @@ pigx-common-transaction ${pigx.version} + + com.pig4cloud + pigx-common-test + ${pigx.version} + com.pig4cloud pigx-upms-api diff --git a/pigx-common/pigx-common-test/pom.xml b/pigx-common/pigx-common-test/pom.xml new file mode 100755 index 000000000..0b623405c --- /dev/null +++ b/pigx-common/pigx-common-test/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + com.pig4cloud + pigx-common + 3.10.0 + + + pigx-common-test + jar + + pigx oauth 2.0 单元测试工具类 + + + + com.pig4cloud + pigx-common-security + + + org.springframework.security + spring-security-test + + + \ No newline at end of file diff --git a/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/WithMockSecurityContextFactory.java b/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/WithMockSecurityContextFactory.java new file mode 100644 index 000000000..0460191c1 --- /dev/null +++ b/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/WithMockSecurityContextFactory.java @@ -0,0 +1,93 @@ +package com.pig4cloud.pigx.test; + +import cn.hutool.http.HttpRequest; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.pig4cloud.pigx.common.core.constant.SecurityConstants; +import com.pig4cloud.pigx.common.core.util.SpringContextHolder; +import com.pig4cloud.pigx.common.security.service.PigxUser; +import com.pig4cloud.pigx.test.annotation.WithMockOAuth2User; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.oauth2.client.OAuth2ClientContext; +import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.provider.token.AccessTokenConverter; +import org.springframework.security.test.context.support.WithSecurityContextFactory; + +import java.util.Collection; + +/** + * @author lengleng + * @date 2020/9/22 + *

+ * oauth2 上下文生成处理器 + */ +public class WithMockSecurityContextFactory implements WithSecurityContextFactory { + + @Override + public SecurityContext createSecurityContext(WithMockOAuth2User oAuth2User) { + // 1. 请求认证中心 + JSONObject authResult = request(oAuth2User); + + // 2. 解析认证中心返回报文 + PigxUser principal = parse(authResult); + + // 3. 构建 oauth2 上下文 + SecurityContext context = SecurityContextHolder.createEmptyContext(); + Authentication auth = new UsernamePasswordAuthenticationToken(principal, "N/A", principal.getAuthorities()); + context.setAuthentication(auth); + + // 4. 上下文保存 token + String token = authResult.getStr("access_token"); + DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(token); + OAuth2ClientContext clientContext = SpringContextHolder.getBean(OAuth2ClientContext.class); + clientContext.setAccessToken(accessToken); + return context; + } + + /** + * 请求认证中心 + * @param oAuth2User 账号、密码 + * @return JSONObject + */ + private JSONObject request(WithMockOAuth2User oAuth2User) { + OAuth2ProtectedResourceDetails clientProperties = SpringContextHolder + .getBean(OAuth2ProtectedResourceDetails.class); + + String result = HttpRequest.post(clientProperties.getAccessTokenUri()) + .basicAuth(clientProperties.getClientId(), clientProperties.getClientSecret()) + .form("username", oAuth2User.username()).form("password", oAuth2User.password()) + .form("grant_type", "password").form("scope", clientProperties.getScope()).execute().body(); + + return JSONUtil.parseObj(result); + } + + /** + * 请求认证中心 + * @param tokenObj 认证中心返回结果 + * @return 用户信息 + */ + private PigxUser parse(JSONObject tokenObj) { + JSONObject userInfo = tokenObj.getJSONObject("user_info"); + + Integer id = userInfo.getInt(SecurityConstants.DETAILS_USER_ID); + Integer deptId = userInfo.getInt(SecurityConstants.DETAILS_DEPT_ID); + String phone = userInfo.getStr(SecurityConstants.DETAILS_PHONE); + String avatar = userInfo.getStr(SecurityConstants.DETAILS_AVATAR); + String username = userInfo.getStr(SecurityConstants.DETAILS_USERNAME); + Integer tenantId = userInfo.getInt(SecurityConstants.DETAILS_TENANT_ID); + JSONArray jsonArray = userInfo.getJSONArray(AccessTokenConverter.AUTHORITIES); + + Collection authorities = AuthorityUtils + .createAuthorityList(jsonArray.toArray(new String[0])); + + return new PigxUser(id, deptId, phone, avatar, tenantId, username, "N/A", true, true, true, true, authorities); + } + +} diff --git a/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/annotation/WithMockOAuth2User.java b/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/annotation/WithMockOAuth2User.java new file mode 100644 index 000000000..23bc599f8 --- /dev/null +++ b/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/annotation/WithMockOAuth2User.java @@ -0,0 +1,29 @@ +package com.pig4cloud.pigx.test.annotation; + +import com.pig4cloud.pigx.test.WithMockSecurityContextFactory; +import org.springframework.security.test.context.support.WithSecurityContext; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * @author lengleng + * @date 2020/9/22 + *

+ * WithMockOAuth2User 注解 + */ +@Retention(RetentionPolicy.RUNTIME) +@WithSecurityContext(factory = WithMockSecurityContextFactory.class) +public @interface WithMockOAuth2User { + + /** + * 用户名 + */ + String username() default "admin"; + + /** + * 密码 + */ + String password() default "123456"; + +} \ No newline at end of file diff --git a/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/kit/OAuthKit.java b/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/kit/OAuthKit.java new file mode 100644 index 000000000..ada75a05a --- /dev/null +++ b/pigx-common/pigx-common-test/src/main/java/com/pig4cloud/pigx/test/kit/OAuthKit.java @@ -0,0 +1,29 @@ +package com.pig4cloud.pigx.test.kit; + +import com.pig4cloud.pigx.common.core.util.SpringContextHolder; +import org.springframework.http.HttpHeaders; +import org.springframework.security.oauth2.client.OAuth2ClientContext; +import org.springframework.test.web.servlet.request.RequestPostProcessor; + +/** + * @author lengleng + * @date 2020/9/22 + *

+ * Mocke 工具类 + */ +public class OAuthKit { + + /** + * mock 请求增加统一请求头 + * @return + */ + public static RequestPostProcessor token() { + return mockRequest -> { + OAuth2ClientContext clientContext = SpringContextHolder.getBean(OAuth2ClientContext.class); + String token = clientContext.getAccessToken().getValue(); + mockRequest.addHeader(HttpHeaders.AUTHORIZATION, String.format("Bearer: %s", token)); + return mockRequest; + }; + } + +} diff --git a/pigx-common/pom.xml b/pigx-common/pom.xml index d1b65e20d..22234fc75 100644 --- a/pigx-common/pom.xml +++ b/pigx-common/pom.xml @@ -47,6 +47,7 @@ pigx-common-sentinel pigx-common-sequence pigx-common-swagger + pigx-common-test pigx-common-transaction