spring security 实现微信登录
生活随笔
收集整理的這篇文章主要介紹了
spring security 实现微信登录
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
介紹
上一章講解了如何用QQ實現(xiàn)登錄,這一回講解的是用微信實現(xiàn)登錄。
實現(xiàn)功能
實現(xiàn)微信登錄。
開發(fā)步驟
引入jar包
jar包的引入和QQ引入的jar包一致。
微信實體信息
/*** @author lvhaibao* @description* @date 2019/1/4 0004 9:46*/ @Data public class WeixinUserInfo {/*** 普通用戶的標(biāo)識,對當(dāng)前開發(fā)者帳號唯一*/private String openid;/*** 普通用戶昵稱*/private String nickname;/*** 語言*/private String language;/*** 普通用戶性別,1為男性,2為女性*/private String sex;/*** 普通用戶個人資料填寫的省份*/private String province;/*** 普通用戶個人資料填寫的城市*/private String city;/*** 國家,如中國為CN*/private String country;/*** 用戶頭像,最后一個數(shù)值代表正方形頭像大小(有0、46、64、96、132數(shù)值可選,0代表640*640正方形頭像),用戶沒有頭像時該項為空*/private String headimgurl;/*** 用戶特權(quán)信息,json數(shù)組,如微信沃卡用戶為(chinaunicom)*/private String[] privilege;/*** 用戶統(tǒng)一標(biāo)識。針對一個微信開放平臺帳號下的應(yīng)用,同一用戶的unionid是唯一的。*/private String unionid;獲取微信用戶的api接口和實現(xiàn)
/*** @author lvhaibao* @description* @date 2019/1/4 0004 9:49*/ public interface Weixin {WeixinUserInfo getUserInfo(String openId); }/*** @author lvhaibao* @description* @date 2019/1/4 0004 9:50*/ 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的,所以覆蓋了原來的方法。*/@Overrideprotected List<HttpMessageConverter<?>> getMessageConverters() {List<HttpMessageConverter<?>> messageConverters = super.getMessageConverters();messageConverters.remove(0);messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));return messageConverters;}/*** 獲取微信用戶信息。*/@Overridepublic 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;} }重寫AccessGrant
因為微信和QQ不同,在獲取token的同時,微信也返回了openId。因此要重寫AccessGrant。
/*** 微信的access_token信息。與標(biāo)準(zhǔn)OAuth2協(xié)議不同,微信在獲取access_token時會同時返回openId,并沒有單獨的通過accessToke換取openId的服務(wù)* 所以在這里繼承了標(biāo)準(zhǔn)AccessGrant,添加了openId字段,作為對微信access_token信息的封裝。** @author lvhaibao* @description* @date 2019/1/4 0004 9:53*/ @Data 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);} }重寫OAuth2Template
/*** @author lvhaibao* @description 重寫OAuth2Template* @date 2019/1/4 0004 10:00*/ @Slf4j 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";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;}/*** 獲取access_token** @param authorizationCode* @param redirectUri* @param parameters* @return*/@Overridepublic AccessGrant exchangeForAccess(String authorizationCode, String redirectUri,MultiValueMap<String, String> 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);}@Overridepublic AccessGrant refreshAccess(String refreshToken, MultiValueMap<String, String> 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) {log.info("獲取access_token, 請求URL: " + accessTokenRequestUrl.toString());//發(fā)送獲取tokenString response = getRestTemplate().getForObject(accessTokenRequestUrl.toString(), String.class);log.info("獲取access_token, 響應(yīng)內(nèi)容: " + response);Map<String, Object> 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);}//獲取token的時候,會返回openid,保存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;}/*** 構(gòu)建獲取授權(quán)碼的請求。也就是引導(dǎo)用戶跳轉(zhuǎn)到微信的地址。*/@Overridepublic String buildAuthenticateUrl(OAuth2Parameters parameters) {String url = super.buildAuthenticateUrl(parameters);url = url + "&appid=" + clientId + "&scope=snsapi_login";return url;}@Overridepublic String buildAuthorizeUrl(OAuth2Parameters parameters) {return buildAuthenticateUrl(parameters);}/*** 微信返回的contentType是html/text,添加相應(yīng)的HttpMessageConverter來處理。*/@Overrideprotected RestTemplate createRestTemplate() {RestTemplate restTemplate = super.createRestTemplate();restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8")));return restTemplate;} }編寫自己的WeixinServiceProvider
/*** 微信的OAuth2流程處理器的提供器,供spring social的connect體系調(diào)用** @author lvhaibao* @description* @date 2019/1/4 0004 10:02*/ public class WeixinServiceProvider extends AbstractOAuth2ServiceProvider<Weixin> {/*** 微信獲取授權(quán)碼的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));}@Overridepublic Weixin getApi(String accessToken) {return new WeixinImpl(accessToken);} }編寫自己的WeixinAdapter
/*** 微信 api適配器,將微信 api的數(shù)據(jù)模型轉(zhuǎn)為spring social的標(biāo)準(zhǔn)模型。** @author lvhaibao* @description* @date 2019/1/4 0004 9:56*/ public class WeixinAdapter implements ApiAdapter<Weixin> {private String openId;public WeixinAdapter() {}public WeixinAdapter(String openId){this.openId = openId;}/*** @param api* @return*/@Overridepublic boolean test(Weixin api) {return true;}/*** @param api* @param values*/@Overridepublic 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*/@Overridepublic UserProfile fetchUserProfile(Weixin api) {return null;}/*** @param api* @param message*/@Overridepublic void updateStatus(Weixin api, String message) {//do nothing} }微信連接工廠ConnectionFactory
/*** @author lvhaibao* @description 創(chuàng)建連接工廠* @date 2019/1/4 0004 9:59*/ public class WeixinConnectionFactory extends OAuth2ConnectionFactory<Weixin> {/*** @param appId* @param appSecret*/public WeixinConnectionFactory(String providerId, String appId, String appSecret) {super(providerId, new WeixinServiceProvider(appId, appSecret), new WeixinAdapter());}/*** 由于微信的openId是和accessToken一起返回的,所以在這里直接根據(jù)accessToken設(shè)置providerUserId即可,不用像QQ那樣通過QQAdapter來獲取*/@Overrideprotected String extractProviderUserId(AccessGrant accessGrant) {if (accessGrant instanceof WeixinAccessGrant) {return ((WeixinAccessGrant) accessGrant).getOpenId();}return null;}@Overridepublic Connection<Weixin> createConnection(AccessGrant accessGrant) {return new OAuth2Connection<Weixin>(getProviderId(), extractProviderUserId(accessGrant), accessGrant.getAccessToken(),accessGrant.getRefreshToken(), accessGrant.getExpireTime(), getOAuth2ServiceProvider(), getApiAdapter(extractProviderUserId(accessGrant)));}@Overridepublic Connection<Weixin> createConnection(ConnectionData data) {return new OAuth2Connection<Weixin>(data, getOAuth2ServiceProvider(), getApiAdapter(data.getProviderUserId()));}private ApiAdapter<Weixin> getApiAdapter(String providerUserId) {return new WeixinAdapter(providerUserId);}private OAuth2ServiceProvider<Weixin> getOAuth2ServiceProvider() {return (OAuth2ServiceProvider<Weixin>) getServiceProvider();} }自定義微信的服務(wù)提供商Id
/*** @author lvhaibao* @description 自定義微信的服務(wù)提供商ID* @date 2019/1/4 0004 9:47*/ @Data public class WeixinProperties extends SocialProperties {private String providerId = "weixin";}編寫配置applicaion.yml
system: #客戶端配置social:filterProcessesUrl: /qqLoginweixin:app-id: wx8a47a66e22296c62app-secret: deb57af7ec1753a2668889e74b34b789頁面
頁面中添加這個鏈接就好。
<a href="/qqLogin/weixin">微信登錄</a>還有其他的配置在上一章中已經(jīng)寫好。讀者可自行查閱或者查看項目源碼。
測試
和QQ登錄一樣。這里就不再進行敘述。
項目源碼
https://gitee.com/lvhaibao/spring-lhbauth/tree/42327d841a8d606bf5b5167c7ecabe72040ec735/
總結(jié)
以上是生活随笔為你收集整理的spring security 实现微信登录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mimic-iii数据库_财务会计应用程
- 下一篇: EasyRecovery14免费激活码序