前言:
根据springBoot自动配置机制可以知道,SpringBoot利用SpringFactories机制,通过SpringFactoriesLoader加载自定义Maven引用工程项目jar包下的META-INF/spring.factories文件,根据文件中所填写的配置类全类名,加载第三方配置类。而这个第三方配置类的作用就是注册所有第三方的Bean,以及加载配置文件信息
第一步:创建配置文件类
配置文件类的作用是读取配置文件中的信息,保存到具体的属性中,方便其他类的使用
那么这个配置信息一般都是在starter被引用的工程中,在application.yaml中对应配置
这也就是在初始化SpringBoot工程的第二步:写配置 (第一步:引Maven)
/**
* @author: 张旭
* @date: 2023/2/22 11:11
* @description: GiteeProperties
*/
@ConfigurationProperties(prefix = "myoauth2login.gitee")
@Data
public class GiteeProperties {
/**
* Client ID,在应用主页可以查看到
*/
private String openidgitee;
/**
* Client Secret
*/
private String openkeygitee;
/**
* 应用回调地址
*/
private String redirectgitee;
}
第二部:创建具体的业务实现类
这里的业务类都不需要加@Component等注解去声明注册Bean,业务类的Bean是在配置类中注册的
- 创建认证授权的父类,主要定义了一些基本方法,如各种类型的发送http请求
public class Oauth {
private String clientId;
private String clientSecret;
private String redirectUri;
public Oauth() {}
/**
* 获取认证Url
* @param authorize 路径地址
* @param params 请求参数
* @return
* @throws UnsupportedEncodingException
*/
protected String getAuthorizeUrl(String authorize, Map<String, String> params) throws UnsupportedEncodingException{
return HttpKit.initParams(authorize, params);
}
protected String doPost(String url, Map<String, String> params) throws IOException, KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException {
return HttpKit.post(url, params);
}
protected String doGet(String url, Map<String, String> params) throws IOException, KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException {
return HttpKit.get(url, params);
}
protected String doGetWithHeaders(String url, Map<String, String> headers) throws IOException, KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException {
return HttpKit.get(url, null, headers);
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getRedirectUri() {
return redirectUri;
}
public void setRedirectUri(String redirectUri) {
this.redirectUri = redirectUri;
}
}
- 创建具体第三方登录授权业务类
public class Oauth2Gitee extends Oauth {
private GiteeProperties giteeProperties;
private static final String AUTH_URL = "https://gitee.com/oauth/authorize";
private static final String TOKEN_URL = "https://gitee.com/oauth/token";
private static final String TOKEN_INFO_URL = "https://api.weibo.com/oauth2/get_token_info";
private static final String USER_INFO_URL = "https://gitee.com/api/v5/user";
public Oauth2Gitee(GiteeProperties giteeProperties) {
this.giteeProperties = giteeProperties;
this.setClientId(giteeProperties.getOpenidgitee());
this.setClientSecret(giteeProperties.getOpenkeygitee());
this.setRedirectUri(giteeProperties.getRedirectgitee());
}
/**
* @param @return 设定文件
* @return String 返回类型
* @throws UnsupportedEncodingException 获取授权url
* DOC:https://gitee.com/api/v5/oauth_doc#/
* @throws
*/
public String getAuthorizeUrl(String state) throws UnsupportedEncodingException {
Map<String, String> params = new HashMap<String, String>();
params.put("response_type", "code");
params.put("client_id", getClientId());
params.put("redirect_uri", getRedirectUri());
if (StringUtils.isNotBlank(state)) {
//OAuth2.0标准协议建议,利用state参数来防止CSRF攻击。可存储于session或其他cache中
params.put("state", state);
}
return super.getAuthorizeUrl(AUTH_URL, params);
}
/**
* @param @param code
* @param @return 设定文件
* @return String 返回类型
* @throws NoSuchProviderException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException 获取token
* @throws
*/
public String getTokenByCode(String code) throws IOException, KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException {
Map<String, String> params = new HashMap<String, String>();
params.put("code", code);
params.put("client_id", getClientId());
params.put("client_secret", getClientSecret());
params.put("grant_type", "authorization_code");
params.put("redirect_uri", getRedirectUri());
String token = TokenUtil.getAccessToken(super.doPost(TOKEN_URL, params));
return token;
}
/**
* @param accessToken
* @return String 返回类型
* @throws NoSuchProviderException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException 获取用户信息
* DOC:https://gitee.com/api/v5/swagger#/getV5User
* @throws
*/
public String getUserInfo(String accessToken) throws IOException, KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException {
Map<String, String> params = new HashMap<String, String>();
params.put("access_token", accessToken);
String userInfo = super.doGet(USER_INFO_URL, params);
return userInfo;
}
}
第三步:创建自动配置类
@Configuration
@EnableConfigurationProperties(GiteeProperties.class)
@ConditionalOnProperty(prefix = "myoauth2login" ,value = "gitee" , matchIfMissing = true)
public class Oauth2GiteeAutoConfiguration {
@Resource
private GiteeProperties properties;
@Bean
@ConditionalOnMissingBean
public Oauth2Gitee oauth2Gitee(){
return new Oauth2Gitee(properties);
}
}
第四步:创建META-INF/spring.factories文件
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xu.oauth2Login.config.Oauth2GiteeAutoConfiguration
至此,基本的自定义starter内容已经完成,进行Maven打包上传即可被第三方使用
注意事项
- 由于配置文件类中有业务类需要使用到的信息,所有业务类需要将配置类作为自己的属性来使用其中的信息,因此需要创建有参构造器,在初始化的时候就传入配置类。
public class Oauth2Gitee extends Oauth {
private GiteeProperties giteeProperties;
public Oauth2Gitee(GiteeProperties giteeProperties) {
this.giteeProperties = giteeProperties;
this.setClientId(giteeProperties.getOpenidgitee());
this.setClientSecret(giteeProperties.getOpenkeygitee());
this.setRedirectUri(giteeProperties.getRedirectgitee());
}
}
public class Oauth2GiteeAutoConfiguration {
@Resource
private GiteeProperties properties;
@Bean
@ConditionalOnMissingBean
public Oauth2Gitee oauth2Gitee(){
return new Oauth2Gitee(properties);
}
}
- 在配置类中注册业务类Bean的时候,最好是加上一些判断条件,来实现Bean的条件注入,如@ConditionalOnMissingBean
@Bean
@ConditionalOnMissingBean
public Oauth2Gitee oauth2Gitee(){
return new Oauth2Gitee(properties);
}