提交 6d50fc99 编写于 作者: zlt2000's avatar zlt2000

优化OIDC协议

上级 7431a35e
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 {
}
......@@ -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";
}
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
* <p>
* 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";
}
......@@ -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<String, Object> 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;
};
}
}
......@@ -99,7 +99,8 @@ zlt:
/api-uaa/images/**,
/api-uaa/js/**,
/login.html,
/user/login
/user/login,
/api-uaa/tokens/key
auth:
urlPermission:
#是否开启url级别权限
......
......@@ -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<String> responseTypes = authentication.getOAuth2Request().getResponseTypes();
if (responseTypes.contains(SecurityConstants.ID_TOKEN)
|| "authJwt".equals(tokenStoreType)) {
|| "authJwt".equals(tokenStoreProperties.getType())) {
Map<String, Object> 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();
......
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<TokenVo> list(@RequestParam Map<String, Object> params, String tenantId) {
return tokensService.listTokens(params, tenantId);
}
@GetMapping("/key")
@ApiOperation(value = "获取jwt密钥")
public Result<String> 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());
}
}
}
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<String> 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;
......
......@@ -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}
*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册