diff --git a/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/config/SecurityPropertiesConfig.java b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/config/SecurityPropertiesConfig.java index fc4448d67816971127c10ac1fc2ffe28598196ef..e579e444cb8e6cbd834462bd5e709878942762d9 100644 --- a/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/config/SecurityPropertiesConfig.java +++ b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/config/SecurityPropertiesConfig.java @@ -1,6 +1,7 @@ package com.central.oauth2.common.config; import com.central.oauth2.common.properties.SecurityProperties; +import com.central.oauth2.common.properties.TokenStoreProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; /** @@ -10,6 +11,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties * Blog: https://zlt2000.gitee.io * Github: https://github.com/zlt2000 */ -@EnableConfigurationProperties(SecurityProperties.class) +@EnableConfigurationProperties({SecurityProperties.class, TokenStoreProperties.class}) public class SecurityPropertiesConfig { } diff --git a/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/constants/IdTokenClaimNames.java b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/constants/IdTokenClaimNames.java index ff4fd46f748ee50b139ff2227c69f1bb732fbee6..23865987397d45d0337ed0bc48f37c2fb8f62fb8 100644 --- a/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/constants/IdTokenClaimNames.java +++ b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/constants/IdTokenClaimNames.java @@ -71,4 +71,19 @@ public class IdTokenClaimNames { * {@code c_hash} - the Authorization Code hash value */ public final static String C_HASH = "c_hash"; + + /** + * {@code name} - 用户姓名 + */ + public final static String NAME = "name"; + + /** + * {@code login_name} - 登录名 + */ + public final static String L_NAME = "login_name"; + + /** + * {@code picture} - 头像照片 + */ + public final static String PIC = "picture"; } diff --git a/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/properties/TokenStoreProperties.java b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/properties/TokenStoreProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..0f2687fbb08933d216745bddbcaf23520482e718 --- /dev/null +++ b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/properties/TokenStoreProperties.java @@ -0,0 +1,27 @@ +package com.central.oauth2.common.properties; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; + +/** + * Token配置 + * + * @author zlt + * @version 1.0 + * @date 2021/5/19 + *

+ * Blog: https://zlt2000.gitee.io + * Github: https://github.com/zlt2000 + */ +@Setter +@Getter +@ConfigurationProperties(prefix = "zlt.oauth2.token.store") +@RefreshScope +public class TokenStoreProperties { + /** + * token存储类型(redis/db/authJwt/resJwt) + */ + private String type = "redis"; +} diff --git a/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/AuthJwtTokenStore.java b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/AuthJwtTokenStore.java index 3b3ce1b141ed017c81b3fe7e9a64a3527d263849..3ad319ed877dd70ca0a93c05a214565f66ed4e0a 100644 --- a/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/AuthJwtTokenStore.java +++ b/zlt-commons/zlt-auth-client-spring-boot-starter/src/main/java/com/central/oauth2/common/store/AuthJwtTokenStore.java @@ -56,26 +56,4 @@ public class AuthJwtTokenStore { tokenConverter.setUserTokenConverter(new CustomUserAuthenticationConverter()); return converter; } - - /** - * jwt 生成token 定制化处理 - * 添加一些额外的用户信息到token里面 - * - * @return TokenEnhancer - */ - @Bean - @Order(1) - public TokenEnhancer tokenEnhancer() { - return (accessToken, authentication) -> { - final Map additionalInfo = new HashMap<>(1); - Object principal = authentication.getPrincipal(); - //增加id参数 - if (principal instanceof SysUser) { - SysUser user = (SysUser)principal; - additionalInfo.put("id", user.getId()); - } - ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); - return accessToken; - }; - } } diff --git a/zlt-gateway/sc-gateway/src/main/resources/application.yml b/zlt-gateway/sc-gateway/src/main/resources/application.yml index 9425c8cfae7d001f8deaf1d11375437d5599cdb1..f7f69bf3f96da7098e6bdf40ef4843a1ecc65394 100644 --- a/zlt-gateway/sc-gateway/src/main/resources/application.yml +++ b/zlt-gateway/sc-gateway/src/main/resources/application.yml @@ -99,7 +99,8 @@ zlt: /api-uaa/images/**, /api-uaa/js/**, /login.html, - /user/login + /user/login, + /api-uaa/tokens/key auth: urlPermission: #是否开启url级别权限 diff --git a/zlt-uaa/src/main/java/com/central/oauth/config/AuthorizationServerConfig.java b/zlt-uaa/src/main/java/com/central/oauth/config/AuthorizationServerConfig.java index 41306120bc205d5d352cb1f08c57dc80897123f6..d9f8c2a6dd97740c0ffea391380528eb090fe6f3 100644 --- a/zlt-uaa/src/main/java/com/central/oauth/config/AuthorizationServerConfig.java +++ b/zlt-uaa/src/main/java/com/central/oauth/config/AuthorizationServerConfig.java @@ -7,8 +7,8 @@ import com.central.oauth.service.IClientService; import com.central.oauth.service.impl.RedisClientDetailsService; import com.central.oauth.utils.OidcIdTokenBuilder; import com.central.oauth2.common.constants.IdTokenClaimNames; +import com.central.oauth2.common.properties.TokenStoreProperties; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.cloud.bootstrap.encrypt.KeyProperties; import org.springframework.context.annotation.Bean; @@ -71,9 +71,6 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap @Autowired private TokenGranter tokenGranter; - @Value("${zlt.oauth2.token.store.type:'redis'}") - private String tokenStoreType; - /** * 配置身份认证器,配置认证方式,TokenStore,TokenGranter,OAuth2RequestFactory * @param endpoints @@ -116,11 +113,12 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap @Bean @Order(1) public TokenEnhancer tokenEnhancer(@Autowired(required = false) KeyProperties keyProperties - , IClientService clientService) { + , IClientService clientService + , TokenStoreProperties tokenStoreProperties) { return (accessToken, authentication) -> { Set responseTypes = authentication.getOAuth2Request().getResponseTypes(); if (responseTypes.contains(SecurityConstants.ID_TOKEN) - || "authJwt".equals(tokenStoreType)) { + || "authJwt".equals(tokenStoreProperties.getType())) { Map additionalInfo = new HashMap<>(2); Object principal = authentication.getPrincipal(); //增加id参数 @@ -130,7 +128,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap //生成id_token setIdToken(additionalInfo, authentication, keyProperties, clientService, user); } - if ("authJwt".equals(tokenStoreType)) { + if ("authJwt".equals(tokenStoreProperties.getType())) { additionalInfo.put("id", user.getId()); } } @@ -160,6 +158,9 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap .issuedAt(now) .expiresAt(expiresAt) .subject(String.valueOf(user.getId())) + .name(user.getNickname()) + .loginName(user.getUsername()) + .picture(user.getHeadImgUrl()) .audience(clientId) .nonce(nonce) .build(); diff --git a/zlt-uaa/src/main/java/com/central/oauth/controller/TokensController.java b/zlt-uaa/src/main/java/com/central/oauth/controller/TokensController.java index 53611a4c01c70ed34a7812fd7ffcbc3fe0bf276f..86cd356a153e56353fa9d845a36055f54adfc427 100644 --- a/zlt-uaa/src/main/java/com/central/oauth/controller/TokensController.java +++ b/zlt-uaa/src/main/java/com/central/oauth/controller/TokensController.java @@ -1,15 +1,28 @@ package com.central.oauth.controller; -import com.central.common.annotation.LoginClient; +import com.central.common.constant.SecurityConstants; import com.central.common.model.PageResult; +import com.central.common.model.Result; import com.central.oauth.model.TokenVo; import com.central.oauth.service.ITokensService; +import com.central.oauth2.common.util.AuthUtils; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.ClientDetailsService; import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.util.Map; +import java.util.stream.Collectors; /** * token管理接口 @@ -17,15 +30,39 @@ import java.util.Map; * @author zlt */ @Api(tags = "Token管理") +@Slf4j @RestController @RequestMapping("/tokens") public class TokensController { - @Autowired + @Resource private ITokensService tokensService; + @Resource + private ClientDetailsService clientDetailsService; + + @Resource + private PasswordEncoder passwordEncoder; + @GetMapping("") @ApiOperation(value = "token列表") public PageResult list(@RequestParam Map params, String tenantId) { return tokensService.listTokens(params, tenantId); } + + @GetMapping("/key") + @ApiOperation(value = "获取jwt密钥") + public Result key(HttpServletRequest request) { + String[] clientArr = AuthUtils.extractClient(request); + ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientArr[0]); + if (!passwordEncoder.matches(clientArr[1], clientDetails.getClientSecret())) { + throw new BadCredentialsException("应用密码错误"); + } + org.springframework.core.io.Resource res = new ClassPathResource(SecurityConstants.RSA_PUBLIC_KEY); + try (BufferedReader br = new BufferedReader(new InputStreamReader(res.getInputStream()))) { + return Result.succeed(br.lines().collect(Collectors.joining("\n"))); + } catch (IOException ioe) { + log.error("key error", ioe); + return Result.failed(ioe.getMessage()); + } + } } diff --git a/zlt-uaa/src/main/java/com/central/oauth/service/impl/CustomTokenServices.java b/zlt-uaa/src/main/java/com/central/oauth/service/impl/CustomTokenServices.java index aef53516e873d8640c359566c1118cf0156f1eb1..4f9f46ee23834b20c626aaa7ab14ac4928d2c396 100644 --- a/zlt-uaa/src/main/java/com/central/oauth/service/impl/CustomTokenServices.java +++ b/zlt-uaa/src/main/java/com/central/oauth/service/impl/CustomTokenServices.java @@ -1,5 +1,6 @@ package com.central.oauth.service.impl; +import com.central.common.constant.SecurityConstants; import org.springframework.security.core.AuthenticationException; import org.springframework.security.oauth2.common.*; import org.springframework.security.oauth2.provider.OAuth2Authentication; @@ -9,6 +10,7 @@ import org.springframework.security.oauth2.provider.token.TokenStore; import org.springframework.transaction.annotation.Transactional; import java.util.Date; +import java.util.Set; import java.util.UUID; /** @@ -55,6 +57,8 @@ public class CustomTokenServices extends DefaultTokenServices { tokenStore.removeAccessToken(existingAccessToken); } else { + // oidc每次授权都刷新id_token + existingAccessToken = refreshIdToken(existingAccessToken, authentication); // Re-store the access token in case the authentication has changed tokenStore.storeAccessToken(existingAccessToken, authentication); return existingAccessToken; @@ -89,6 +93,19 @@ public class CustomTokenServices extends DefaultTokenServices { } + /** + * oidc每次授权都刷新id_token + * @param token 已存在的token + * @param authentication 认证信息 + */ + private OAuth2AccessToken refreshIdToken(OAuth2AccessToken token, OAuth2Authentication authentication) { + Set responseTypes = authentication.getOAuth2Request().getResponseTypes(); + if (accessTokenEnhancer != null && responseTypes.contains(SecurityConstants.ID_TOKEN)) { + return accessTokenEnhancer.enhance(token, authentication); + } + return token; + } + private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) { if (!isSupportRefreshToken(authentication.getOAuth2Request())) { return null; diff --git a/zlt-uaa/src/main/java/com/central/oauth/utils/OidcIdTokenBuilder.java b/zlt-uaa/src/main/java/com/central/oauth/utils/OidcIdTokenBuilder.java index 1f732c560c2e124b635da16639000b213103e7a8..f38694bb9ba22c81b41e159ca2287f0a12b98c49 100644 --- a/zlt-uaa/src/main/java/com/central/oauth/utils/OidcIdTokenBuilder.java +++ b/zlt-uaa/src/main/java/com/central/oauth/utils/OidcIdTokenBuilder.java @@ -100,6 +100,27 @@ public class OidcIdTokenBuilder { return this.claim(SUB, subject); } + /** + * 赋值用户姓名 + */ + public OidcIdTokenBuilder name(String name) { + return this.claim(NAME, name); + } + + /** + * 赋值用户登录名 + */ + public OidcIdTokenBuilder loginName(String loginName) { + return this.claim(L_NAME, loginName); + } + + /** + * 赋值用户头像 + */ + public OidcIdTokenBuilder picture(String picture) { + return this.claim(PIC, picture); + } + /** * Build the {@link OidcIdTokenBuilder} *