SpringSocial開発微信ログイン
14548 ワード
この記事ではSpringBoot 2に基づいて説明します.0,SpringSocial開発微信登録.大部分は実はQQと登録してとても似ていて、原理は贅沢に述べなくて、みんなが先にSpringSocialを見てQQを開発して実戦編に登録することを許可することを提案します
1.Api開発
1.1ユーザ情報取得インタフェースの宣言
1.2WeixinUserInfo
1.3ユーザ情報インタフェース実装クラスの取得
OK、API部分の開発が完了し、QQとの違いが最も大きいのは、openIdを取得していないことです.そして、getUserInfoにはopenIdパラメータが1つ増えています.なぜopenIdを取得する必要がありませんか.WeChatがライセンスコードでtokenを入手してopenIdも持ち帰ったので、手順2 OAuthOperations開発2.1 WeixinOAuth 2 Templateを省いてくれました
2.2 WeixinAccessGrant
3 ServiceProvider
4.ApiAdapter
5. OAuth2ConnectionFactory
6 SocialConfigの構成
微信の配置とQQの差は多くなく、ここではコードを貼り付けるだけで、具体的な疑問点は前の文章を参考にすることができます.
1.Api開発
1.1ユーザ情報取得インタフェースの宣言
public interface Weixin {
WeixinUserInfo getUserInfo(String openId);
}
1.2WeixinUserInfo
public class WeixinUserInfo {
/**
* ,
*/
private String openid;
/**
*
*/
private String nickname;
/**
*
*/
private String language;
/**
* ,1 ,2
*/
private String sex;
/**
*
*/
private String province;
/**
*
*/
private String city;
/**
* , CN
*/
private String country;
/**
* , ( 0、46、64、96、132 ,0 640*640 ),
*/
private String headimgurl;
/**
* ,json , (chinaunicom)
*/
private String[] privilege;
/**
* 。 , unionid 。
*/
private String unionid;
1.3ユーザ情報インタフェース実装クラスの取得
public class WeixinImpl extends AbstractOAuth2ApiBinding implements Weixin {
/**
*
*/
private ObjectMapper objectMapper = new ObjectMapper();
/**
* url
*/
private static final String URL_GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?openid=";
/**
* @param accessToken
*/
public WeixinImpl(String accessToken) {
super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
}
/**
* StringHttpMessageConverter ISO-8859-1, UTF-8 , 。
*/
protected List> getMessageConverters() {
List> messageConverters = super.getMessageConverters();
messageConverters.remove(0);
messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
return messageConverters;
}
/**
* 。
*/
@Override
public WeixinUserInfo getUserInfo(String openId) {
String url = URL_GET_USER_INFO + openId;
String response = getRestTemplate().getForObject(url, String.class);
if(StringUtils.contains(response, "errcode")) {
return null;
}
WeixinUserInfo profile = null;
try {
profile = objectMapper.readValue(response, WeixinUserInfo.class);
} catch (Exception e) {
e.printStackTrace();
}
return profile;
}
}
OK、API部分の開発が完了し、QQとの違いが最も大きいのは、openIdを取得していないことです.そして、getUserInfoにはopenIdパラメータが1つ増えています.なぜopenIdを取得する必要がありませんか.WeChatがライセンスコードでtokenを入手してopenIdも持ち帰ったので、手順2 OAuthOperations開発2.1 WeixinOAuth 2 Templateを省いてくれました
public class WeixinOAuth2Template extends OAuth2Template {
private String clientId;
private String clientSecret;
private String accessTokenUrl;
private static final String REFRESH_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
private Logger logger = LoggerFactory.getLogger(getClass());
public WeixinOAuth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) {
super(clientId, clientSecret, authorizeUrl, accessTokenUrl);
setUseParametersForClientAuthentication(true);
this.clientId = clientId;
this.clientSecret = clientSecret;
this.accessTokenUrl = accessTokenUrl;
}
/* (non-Javadoc)
* @see org.springframework.social.oauth2.OAuth2Template#exchangeForAccess(java.lang.String, java.lang.String, org.springframework.util.MultiValueMap)
*/
@Override
public AccessGrant exchangeForAccess(String authorizationCode, String redirectUri,
MultiValueMap parameters) {
StringBuilder accessTokenRequestUrl = new StringBuilder(accessTokenUrl);
accessTokenRequestUrl.append("?appid="+clientId);
accessTokenRequestUrl.append("&secret="+clientSecret);
accessTokenRequestUrl.append("&code="+authorizationCode);
accessTokenRequestUrl.append("&grant_type=authorization_code");
accessTokenRequestUrl.append("&redirect_uri="+redirectUri);
return getAccessToken(accessTokenRequestUrl);
}
public AccessGrant refreshAccess(String refreshToken, MultiValueMap additionalParameters) {
StringBuilder refreshTokenUrl = new StringBuilder(REFRESH_TOKEN_URL);
refreshTokenUrl.append("?appid="+clientId);
refreshTokenUrl.append("&grant_type=refresh_token");
refreshTokenUrl.append("&refresh_token="+refreshToken);
return getAccessToken(refreshTokenUrl);
}
@SuppressWarnings("unchecked")
private AccessGrant getAccessToken(StringBuilder accessTokenRequestUrl) {
logger.info(" access_token, URL: "+accessTokenRequestUrl.toString());
String response = getRestTemplate().getForObject(accessTokenRequestUrl.toString(), String.class);
logger.info(" access_token, : "+response);
Map result = null;
try {
result = new ObjectMapper().readValue(response, Map.class);
} catch (Exception e) {
e.printStackTrace();
}
//
if(StringUtils.isNotBlank(MapUtils.getString(result, "errcode"))){
String errcode = MapUtils.getString(result, "errcode");
String errmsg = MapUtils.getString(result, "errmsg");
throw new RuntimeException(" access token , errcode:"+errcode+", errmsg:"+errmsg);
}
WeixinAccessGrant accessToken = new WeixinAccessGrant(
MapUtils.getString(result, "access_token"),
MapUtils.getString(result, "scope"),
MapUtils.getString(result, "refresh_token"),
MapUtils.getLong(result, "expires_in"));
accessToken.setOpenId(MapUtils.getString(result, "openid"));
return accessToken;
}
/**
* 。 。
*/
public String buildAuthenticateUrl(OAuth2Parameters parameters) {
String url = super.buildAuthenticateUrl(parameters);
url = url + "&appid="+clientId+"&scope=snsapi_login";
return url;
}
public String buildAuthorizeUrl(OAuth2Parameters parameters) {
return buildAuthenticateUrl(parameters);
}
/**
* contentType html/text, HttpMessageConverter 。
*/
protected RestTemplate createRestTemplate() {
RestTemplate restTemplate = super.createRestTemplate();
restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}
}
2.2 WeixinAccessGrant
public class WeixinAccessGrant extends AccessGrant {
/**
*
*/
private static final long serialVersionUID = -7243374526633186782L;
private String openId;
public WeixinAccessGrant() {
super("");
}
public WeixinAccessGrant(String accessToken, String scope, String refreshToken, Long expiresIn) {
super(accessToken, scope, refreshToken, expiresIn);
}
/**
* @return the openId
*/
public String getOpenId() {
return openId;
}
/**
* @param openId the openId to set
*/
public void setOpenId(String openId) {
this.openId = openId;
}
}
3 ServiceProvider
public class WeixinServiceProvider extends AbstractOAuth2ServiceProvider {
/**
* url
*/
private static final String URL_AUTHORIZE = "https://open.weixin.qq.com/connect/qrconnect";
/**
* accessToken url
*/
private static final String URL_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token";
/**
* @param appId
* @param appSecret
*/
public WeixinServiceProvider(String appId, String appSecret) {
super(new WeixinOAuth2Template(appId, appSecret,URL_AUTHORIZE,URL_ACCESS_TOKEN));
}
/* (non-Javadoc)
* @see org.springframework.social.oauth2.AbstractOAuth2ServiceProvider#getApi(java.lang.String)
*/
@Override
public Weixin getApi(String accessToken) {
return new WeixinImpl(accessToken);
}
}
4.ApiAdapter
public class WeixinAdapter implements ApiAdapter {
private String openId;
public WeixinAdapter() {}
public WeixinAdapter(String openId){
this.openId = openId;
}
/**
* @param api
* @return
*/
@Override
public boolean test(Weixin api) {
return true;
}
/**
* @param api
* @param values
*/
@Override
public void setConnectionValues(Weixin api, ConnectionValues values) {
WeixinUserInfo profile = api.getUserInfo(openId);
values.setProviderUserId(profile.getOpenid());
values.setDisplayName(profile.getNickname());
values.setImageUrl(profile.getHeadimgurl());
}
/**
* @param api
* @return
*/
@Override
public UserProfile fetchUserProfile(Weixin api) {
return null;
}
/**
* @param api
* @param message
*/
@Override
public void updateStatus(Weixin api, String message) {
//do nothing
}
}
5. OAuth2ConnectionFactory
public class WeixinConnectionFactory extends OAuth2ConnectionFactory {
/**
* @param appId
* @param appSecret
*/
public WeixinConnectionFactory(String providerId, String appId, String appSecret) {
super(providerId, new WeixinServiceProvider(appId, appSecret), new WeixinAdapter());
}
/**
* openId accessToken , accessToken providerUserId , QQ QQAdapter
*/
@Override
protected String extractProviderUserId(AccessGrant accessGrant) {
if(accessGrant instanceof WeixinAccessGrant) {
return ((WeixinAccessGrant)accessGrant).getOpenId();
}
return null;
}
/* (non-Javadoc)
* @see org.springframework.social.connect.support.OAuth2ConnectionFactory#createConnection(org.springframework.social.oauth2.AccessGrant)
*/
public Connection createConnection(AccessGrant accessGrant) {
return new OAuth2Connection(getProviderId(), extractProviderUserId(accessGrant), accessGrant.getAccessToken(),
accessGrant.getRefreshToken(), accessGrant.getExpireTime(), getOAuth2ServiceProvider(), getApiAdapter(extractProviderUserId(accessGrant)));
}
/* (non-Javadoc)
* @see org.springframework.social.connect.support.OAuth2ConnectionFactory#createConnection(org.springframework.social.connect.ConnectionData)
*/
public Connection createConnection(ConnectionData data) {
return new OAuth2Connection(data, getOAuth2ServiceProvider(), getApiAdapter(data.getProviderUserId()));
}
private ApiAdapter getApiAdapter(String providerUserId) {
return new WeixinAdapter(providerUserId);
}
private OAuth2ServiceProvider getOAuth2ServiceProvider() {
return (OAuth2ServiceProvider) getServiceProvider();
}
}
6 SocialConfigの構成
@Configuration
@EnableSocial
@ConditionalOnProperty(prefix = "imooc.security.social.qq", name = "app-id")
public class SocialConfig extends SocialConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private SecurityProperties securityProperties;
@Autowired(required = false)
private ConnectionSignUp connectionSignUp;
@Override
public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource,
connectionFactoryLocator, Encryptors.noOpText());
repository.setTablePrefix("imooc_");
if(connectionSignUp != null) {
repository.setConnectionSignUp(connectionSignUp);
}
return repository;
}
@Bean
public SpringSocialConfigurer imoocSocialSecurityConfig() {
String filterProcessesUrl = securityProperties.getSocial().getFilterProcessesUrl();
ImoocSpringSocialConfigurer configurer = new ImoocSpringSocialConfigurer(filterProcessesUrl);
configurer.signupUrl(securityProperties.getBrowser().getSignUpUrl());
return configurer;
}
@Bean
public ProviderSignInUtils providerSignInUtils(ConnectionFactoryLocator connectionFactoryLocator) {
return new ProviderSignInUtils(connectionFactoryLocator,
getUsersConnectionRepository(connectionFactoryLocator)) {
};
}
@Override
public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer,
Environment environment) {
super.addConnectionFactories(connectionFactoryConfigurer, environment);
QQProperties qqConfig = securityProperties.getSocial().getQq();
WeixinProperties weixinConfig = securityProperties.getSocial().getWeixin();
connectionFactoryConfigurer.addConnectionFactory(
new QQConnectionFactory(qqConfig.getProviderId(), qqConfig.getAppId(), qqConfig.getAppSecret()));
connectionFactoryConfigurer.addConnectionFactory(new WeixinConnectionFactory(weixinConfig.getProviderId(),
weixinConfig.getAppId(), weixinConfig.getAppSecret()));
}
@Override
public UserIdSource getUserIdSource() {
return new AuthenticationNameUserIdSource();
}
}
微信の配置とQQの差は多くなく、ここではコードを貼り付けるだけで、具体的な疑問点は前の文章を参考にすることができます.