在开发oauth时,发现一个问题,就是存在数据库的Client_sercret为密文,虽然这样保证了安全,但是由于我经常忘记定义的是啥,所以想存储为明文。
首先,查看Oauth源码,源码提供两种读取Client的读取方式。
1.如果我们选择默认的Jdbc读取,只需要在数据库中添加官方提供的表即可
2.这里我选择自定义client表,首先实现ClientDetailsService接口
import com.alibaba.fastjson.JSONObject;
import com.lionel.common.api.ISysClientProvider;
import com.lionel.common.api.ISysUserProvider;
import com.lionel.common.entity.SysClient;
import com.lionel.common.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class LionelClientService implements ClientDetailsService {
@Autowired
private ISysClientProvider iSysClientProvider;
@Autowired
private RedisUtil redisUtil;
@Autowired
PasswordEncoder passwordEncoder;
private final String CLIENT_REDIS_KEY = "SYS.CLIENT.";
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
BaseClientDetails details;
try {
SysClient byClientId = this.getOrSaveClientRedis(clientId);
if (Objects.isNull(byClientId)) {
throw new NoSuchClientException("No client with requested id: " + clientId);
}
details = new BaseClientDetails(clientId,
byClientId.getResourceIds(),
byClientId.getScope(),
byClientId.getAuthorizedGrantTypes(),
byClientId.getAuthorities(),
byClientId.getWebServerRedirectUri());
details.setClientSecret(passwordEncoder.encode(byClientId.getClientSecret()));
}
catch (EmptyResultDataAccessException e) {
throw new NoSuchClientException("No client with requested id: " + clientId);
}
return details;
}
/**
* 缓存中读取client
* @param clientId
* @return
*/
public SysClient getOrSaveClientRedis(String clientId) {
Boolean aBoolean = redisUtil.hasKey(CLIENT_REDIS_KEY + clientId);
if (aBoolean) {
String s = redisUtil.get(CLIENT_REDIS_KEY + clientId);
return JSONObject.parseObject(s,SysClient.class);
} else {
// 读取数据库
SysClient byClientId = iSysClientProvider.getByClientId(clientId);
if (Objects.isNull(byClientId)) {
return byClientId;
}
String clientIdJson = JSONObject.toJSONString(byClientId);
redisUtil.set(CLIENT_REDIS_KEY+clientId , clientIdJson);
return byClientId;
}
}
3.在WebSecurityConfigurerAdapter实现类注入bean
@Autowired
private LionelClientService lionelClientService;
@Bean
public ClientDetailsService clientDetailsService() {
return lionelClientService;
}