日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Security源码分析四:Spring Social实现微信社交登录

發布時間:2025/3/8 javascript 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Security源码分析四:Spring Social实现微信社交登录 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

社交登錄又稱作社會化登錄(Social Login),是指網站的用戶可以使用騰訊QQ、人人網、開心網、新浪微博、搜狐微博、騰訊微博、淘寶、豆瓣、MSN、Google等社會化媒體賬號登錄該網站。

前言

在上一章Spring-Security源碼分析三-Spring-Social社交登錄過程中,我們已經實現了使用Spring Social+Security的QQ社交登錄。本章我們將實現微信的社交登錄。(微信和QQ登錄的大體流程相同,但存在一些細節上的差異,下面我們來簡單實現一下)

準備工作

  • 熟悉OAuth2.0協議標準,微信登錄是基于OAuth2.0中的authorization_code模式的授權登錄;
  • 微信開放平臺申請網站應用開發,獲取appid和appsecret
  • 熟讀網站應用微信登錄開發指南
  • 參考Spring-Security源碼分析三-Spring-Social社交登錄過程的準備工作
  • 為了方便大家測試,博主在某寶租用了一個月的appid和appSecret

    appidwxfd6965ab1fc6adb2
    appsecret66bb4566de776ac699ec1dbed0cc3dd1

    目錄結構

    參考

  • api 定義api綁定的公共接口
  • config 微信的一些配置信息
  • connect與服務提供商建立連接所需的一些類。
  • 定義返回用戶信息接口

    public interface Weixin {WeixinUserInfo getUserInfo(String openId); }

    這里我們看到相對于QQ的getUserInfo微信多了一個參數openId。這是因為微信文檔中在OAuth2.0的認證流程示意圖第五步時,微信的openid 同access_token一起返回。而Spring Social獲取access_token的類AccessGrant.java中沒有openid。因此我們自己需要擴展一下Spring Social獲取令牌的類(AccessGrant.java);

    處理微信返回的access_token類(添加openid)

    @Data public class WeixinAccessGrant extends AccessGrant{private String openId;public WeixinAccessGrant() {super("");}public WeixinAccessGrant(String accessToken, String scope, String refreshToken, Long expiresIn) {super(accessToken, scope, refreshToken, expiresIn);} }

    實現返回用戶信息接口

    public class WeiXinImpl extends AbstractOAuth2ApiBinding implements Weixin {/*** 獲取用戶信息的url*/private static final String WEIXIN_URL_GET_USER_INFO = "https://api.weixin.qq.com/sns/userinfo?openid=";private ObjectMapper objectMapper = new ObjectMapper();public WeiXinImpl(String accessToken) {super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);}/*** 獲取用戶信息** @param openId* @return*/@Overridepublic WeixinUserInfo getUserInfo(String openId) {String url = WEIXIN_URL_GET_USER_INFO + openId;String result = getRestTemplate().getForObject(url, String.class);if(StringUtils.contains(result, "errcode")) {return null;}WeixinUserInfo userInfo = null;try{userInfo = objectMapper.readValue(result,WeixinUserInfo.class);}catch (Exception e){e.printStackTrace();}return userInfo;}/*** 使用utf-8 替換默認的ISO-8859-1編碼* @return*/@Overrideprotected List<HttpMessageConverter<?>> getMessageConverters() {List<HttpMessageConverter<?>> messageConverters = super.getMessageConverters();messageConverters.remove(0);messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));return messageConverters;} }

    與QQ獲取用戶信息相比,微信的實現類中少了一步通過access_token獲取openid的請求。openid由自己定義的擴展類WeixinAccessGrant中獲取;

    WeixinOAuth2Template處理微信返回的令牌信息

    @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;}/* (non-Javadoc)* @see org.springframework.social.oauth2.OAuth2Template#exchangeForAccess(java.lang.String, java.lang.String, org.springframework.util.MultiValueMap)*/@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);}public 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());String response = getRestTemplate().getForObject(accessTokenRequestUrl.toString(), String.class);log.info("獲取access_token, 響應內容: "+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);}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;} }

    與QQ處理令牌類相比多了三個全局變量并且復寫了exchangeForAccess方法。這是因為微信在通過code獲取access_token是傳遞的參數是appid和secret而不是標準的client_id和client_secret。

    WeixinServiceProvider連接服務提供商

    public class WeixinServiceProvider extends AbstractOAuth2ServiceProvider<Weixin> {/*** 微信獲取授權碼的url*/private static final String WEIXIN_URL_AUTHORIZE = "https://open.weixin.qq.com/connect/qrconnect";/*** 微信獲取accessToken的url(微信在獲取accessToken時也已經返回openId)*/private static final String WEIXIN_URL_ACCESS_TOKEN = "https://api.weixin.qq.com/sns/oauth2/access_token";public WeixinServiceProvider(String appId, String appSecret) {super(new WeixinOAuth2Template(appId, appSecret, WEIXIN_URL_AUTHORIZE, WEIXIN_URL_ACCESS_TOKEN));}@Overridepublic Weixin getApi(String accessToken) {return new WeiXinImpl(accessToken);} }

    WeixinConnectionFactory連接服務提供商的工廠類

    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一起返回的,所以在這里直接根據accessToken設置providerUserId即可,不用像QQ那樣通過QQAdapter來獲取*/@Overrideprotected 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<Weixin> createConnection(AccessGrant accessGrant) {return new OAuth2Connection<Weixin>(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<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();}}

    WeixinAdapter將微信api返回的數據模型適配Spring Social的標準模型

    public class WeixinAdapter implements ApiAdapter<Weixin> {private String openId;public WeixinAdapter() {}public WeixinAdapter(String openId) {this.openId = openId;}@Overridepublic boolean test(Weixin api) {return true;}@Overridepublic void setConnectionValues(Weixin api, ConnectionValues values) {WeixinUserInfo userInfo = api.getUserInfo(openId);values.setProviderUserId(userInfo.getOpenid());values.setDisplayName(userInfo.getNickname());values.setImageUrl(userInfo.getHeadimgurl());}@Overridepublic UserProfile fetchUserProfile(Weixin api) {return null;}@Overridepublic void updateStatus(Weixin api, String message) {} }

    WeixinAuthConfig創建工廠和設置數據源

    @Configuration public class WeixinAuthConfig extends SocialAutoConfigurerAdapter {@Autowiredprivate DataSource dataSource;@Autowiredprivate ConnectionSignUp myConnectionSignUp;@Overrideprotected ConnectionFactory<?> createConnectionFactory() {return new WeixinConnectionFactory(DEFAULT_SOCIAL_WEIXIN_PROVIDER_ID, SecurityConstants.DEFAULT_SOCIAL_WEIXIN_APP_ID,SecurityConstants.DEFAULT_SOCIAL_WEIXIN_APP_SECRET);}@Overridepublic UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource,connectionFactoryLocator, Encryptors.noOpText());if (myConnectionSignUp != null) {repository.setConnectionSignUp(myConnectionSignUp);}return repository;}/*** /connect/weixin POST請求,綁定微信返回connect/weixinConnected視圖* /connect/weixin DELETE請求,解綁返回connect/weixinConnect視圖* @return*/@Bean({"connect/weixinConnect", "connect/weixinConnected"})@ConditionalOnMissingBean(name = "weixinConnectedView")public View weixinConnectedView() {return new SocialConnectView();}}

    社交登錄配置類

    由于社交登錄都是通過SocialAuthenticationFilter過濾器攔截的,如果 上一章 已經配置過,則本章不需要配置。

    效果如下:

    代碼下載

    從我的 github 中下載,https://github.com/longfeizheng/logback

    轉載于:https://my.oschina.net/merryyou/blog/1606071

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的Spring Security源码分析四:Spring Social实现微信社交登录的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。