Spring-Security-OAuth2调用微信API
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map; @Controller
public class LoginController { @Autowired
private OAuth2ClientContext context; @Bean
@Scope("session")
public OAuth2ClientContext createContext() {
return new DefaultOAuth2ClientContext();
} @ResponseBody
@RequestMapping("/weixin/authorize")
public Object getUserInfo(HttpServletRequest request) {
class WeixinAuthorizationCodeAccessTokenProvider extends AuthorizationCodeAccessTokenProvider {
public WeixinAuthorizationCodeAccessTokenProvider(List<HttpMessageConverter<?>> messageConverters) {
this.setMessageConverters(messageConverters);
this.setTokenRequestEnhancer(new RequestEnhancer() {
@Override
public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) {
String clientId = form.getFirst("client_id");
String clientSecret = form.getFirst("client_secret");
form.set("appid", clientId);
form.set("secret", clientSecret);
form.remove("client_id");
form.remove("client_secret");
}
});
} @Override
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
throws UserRedirectRequiredException, UserApprovalRequiredException,
AccessDeniedException, OAuth2AccessDeniedException {
try {
return super.obtainAccessToken(details, request);
} catch (UserRedirectRequiredException e) {
Map<String, String> params = e.getRequestParams();
String clientId = params.get("client_id");
params.put("appid", clientId);
params.remove("client_id");
throw e;
}
}
} class WeixinOAuth2RestTemplate extends OAuth2RestTemplate { public WeixinOAuth2RestTemplate(AuthorizationCodeResourceDetails resource, OAuth2ClientContext context) {
super(resource, context);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new MappingJackson2HttpMessageConverter() {
@Override
protected boolean canRead(MediaType mediaType) {
return true;
}
});
this.setMessageConverters(messageConverters);
this.setAccessTokenProvider(new WeixinAuthorizationCodeAccessTokenProvider(messageConverters));
} @Override
protected URI appendQueryParameter(URI uri, OAuth2AccessToken accessToken) {
uri = super.appendQueryParameter(uri, accessToken);
String url = uri.toString();
if (url.contains("$openid$")) {
String openid = (String) accessToken.getAdditionalInformation().get("openid");
try {
uri = new URI(url.replace("$openid$", openid));
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
return uri;
} } AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setAuthenticationScheme(AuthenticationScheme.form);
resource.setClientAuthenticationScheme(AuthenticationScheme.form);
resource.setClientId("xxxxxxxxxxx");
resource.setClientSecret("xxxxxxxxxxx");
resource.setUserAuthorizationUri("https://open.weixin.qq.com/connect/oauth2/authorize");
resource.setAccessTokenUri("https://api.weixin.qq.com/sns/oauth2/access_token");
resource.setScope(Arrays.asList("snsapi_userinfo"));
context.getAccessTokenRequest().setCurrentUri(request.getRequestURL().toString()); // resource.setPreEstablishedRedirectUri("http://www.baidu.com"); // resource.setUseCurrentUri(false); OAuth2RestTemplate template = new WeixinOAuth2RestTemplate(resource, context);
String url = "https://api.weixin.qq.com/sns/userinfo?lang=zh_CN&openid=$openid$";
ResponseEntity<Object> result = template.getForEntity(url, Object.class);
return result.getBody();
} }
https://www.cnblogs.com/kingsy/p/6375881.html
class WeixinClientCredentialsAccessTokenProvider extends ClientCredentialsAccessTokenProvider {
public WeixinClientCredentialsAccessTokenProvider() {
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new MappingJackson2HttpMessageConverter());
this.setMessageConverters(converters);
this.setTokenRequestEnhancer(new RequestEnhancer() { @Override
public void enhance(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) {
form.set("appid", resource.getClientId());
form.set("secret", resource.getClientSecret());
form.set("grant_type", "client_credential");
}
}); }
OAuth2ClientContext context = new DefaultOAuth2ClientContext();
ClientCredentialsResourceDetails resource = new ClientCredentialsResourceDetails();
resource.setClientId("xxxxxxxxx");
resource.setClientSecret("xxxxxxxxxxxxxxx");
resource.setAccessTokenUri("https://api.weixin.qq.com/cgi-bin/token");
resource.setAuthenticationScheme(AuthenticationScheme.form);
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource, context);
restTemplate.setAccessTokenProvider(new WeixinClientCredentialsAccessTokenProvider());
restTemplate.setRetryBadAccessTokens(true);
ResponseEntity<Object> response = restTemplate.getForEntity("https://api.weixin.qq.com/cgi-bin/user/get", Object.class);
if (response.getStatusCode() == HttpStatus.OK) {
System.out.println(response.getBody());
}
http://www.cnblogs.com/kingsy/p/6375880.html
使用背景 :公司有个开放平台,若要访问开放平台,必须先要获取授权访问令牌(也就是下面说的:access_token)。公司的授权系统是用spring oauth2.0实现的,今天就不讲这个项目,网上比较多。今天主要是讲下如何用spring OAuth2.0 Client 组件会去实现高效获取access_token。
以下是实现代码:
1.项目启动后,从oauth.properties获取相关的信息(如公钥、私钥等信息),然后实例化OAuth2RestTemplate,主要是通过OAuth2RestTemplate这个类去获取access_token
@EnableOAuth2Client
@Configuration
@Component
public class Oauth2Config{ private final static Logger logger = Logger.getLogger(Oauth2Config.class); private static String location = "classpath:config/*/oauth.properties"; private static Map<String,String> oauthInfo = new HashMap<String,String>(); @Autowired
private OAuth2ClientContext oauth2Context; /**
* 获取配置文件信息
*/
static{
ResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
Resource[] resources;
try {
resources = patternResolver.getResources(location);
location = resources[0].getFile().getAbsolutePath();
logger.info("location" + location);
Properties props = new Properties();
try {
if(location.contains("dev")){
props = PropertiesLoaderUtils.loadAllProperties("config/dev/oauth.properties");
}else if(location.contains("test")){
props = PropertiesLoaderUtils.loadAllProperties("config/test/oauth.properties");
}else if(location.contains("production")){
props = PropertiesLoaderUtils.loadAllProperties("config/production/oauth.properties");
}
for(Object key:props.keySet()){
logger.warn(key + " : " + (String)props.get(key));
oauthInfo.put((String) key, (String)props.get(key));
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
} catch (IOException e) {
e.printStackTrace();
} } @Bean
public AccessTokenRequest accessTokenRequest(){
AccessTokenRequest defaultAccessTokenRequest = new DefaultAccessTokenRequest();
Map<String, List<String>> headers = new HashMap<String, List<String>>();
List<String> headerList=new ArrayList<String>();
headerList.add("Basic " + oauthInfo.get("public_key"));
headers.put("Authorization", headerList);
defaultAccessTokenRequest.setHeaders(headers);
defaultAccessTokenRequest.setCurrentUri(oauthInfo.get("redirect_uri"));
return defaultAccessTokenRequest;
} @Bean
public AuthorizationCodeResourceDetails resourceDetails(){
AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();
resource.setAccessTokenUri(oauthInfo.get("oauth_url") + oauthInfo.get("request_and_refresh_token"));
resource.setClientId(oauthInfo.get("client_id"));
resource.setGrantType("authorization_code");
resource.setUserAuthorizationUri(oauthInfo.get("oauth_url") + oauthInfo.get("request_code_url"));
resource.setScope(Arrays.asList("app"));
resource.setPreEstablishedRedirectUri(oauthInfo.get("redirect_uri"));
return resource;
} @Bean
public OAuth2RestTemplate oAuth2RestTemplate(){
accessTokenRequest().setPreservedState(oauthInfo.get("redirect_uri"));
accessTokenRequest().setStateKey(new DefaultStateKeyGenerator().generateKey(resourceDetails())); AuthorizationCodeAccessTokenProvider provider = new AuthorizationCodeAccessTokenProvider();
provider.setAuthenticationHandler(new ClientAuthenticationHandler() {
@Override
public void authenticateTokenRequest(
OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) {
headers.set("Authorization", "Basic " + oauthInfo.get("private_key") );
}
});
AccessTokenProviderChain providerChain = new AccessTokenProviderChain(Arrays.asList(provider));
//oauth2Context.setPreservedState(accessTokenRequest().getStateKey(),accessTokenRequest().getPreservedState());
OAuth2RestTemplate template=new OAuth2RestTemplate(resourceDetails(),oauth2Context);
template.setAccessTokenProvider(providerChain);
return template;
} }
2.通过OAuth2RestTemplate去获取access_token的值,之所以每次都情况授权code,是因为spring oauth2授权code只能用一次便废弃,然后起OAuth2ClientContext类又不主动清空code,这里我只能自己手动清除。
@Component
public class AccessTokenUtils { private final static Logger logger = Logger.getLogger(AccessTokenUtils.class); @Autowired
private OAuth2RestTemplate restTemplate; @Autowired
private Oauth2Config oauth2Config; /**
* 获取oauth2的授权令牌access_token
* @return
*/
public String getAccessToken(){
logger.info("获取oauth2的授权令牌access_token start ...");
OAuth2ClientContext oAuth2ClientContext = restTemplate.getOAuth2ClientContext();
oAuth2ClientContext.getAccessTokenRequest().setAuthorizationCode(null);//清空授权code
String stateKey = oAuth2ClientContext.getAccessTokenRequest().getStateKey();
Object preservedState = oAuth2ClientContext.getAccessTokenRequest().getPreservedState();
if(StringUtils.isEmpty(stateKey))
stateKey = new DefaultStateKeyGenerator().generateKey(oauth2Config.resourceDetails());
if(preservedState == null )
preservedState = VipConstant.redirtUrl; logger.info("statekey:" + stateKey + " ; preservedState : " + preservedState);
oAuth2ClientContext.setPreservedState(oAuth2ClientContext.getAccessTokenRequest().getStateKey(), oAuth2ClientContext.getAccessTokenRequest().getPreservedState());
OAuth2AccessToken oAuth2AccessToken = this.restTemplate.getAccessToken();
String access_token = oAuth2AccessToken.getValue();
logger.info("获取oauth2的授权令牌access_token end ;access_token = " + access_token + ";失效时间 = " + oAuth2AccessToken.getExpiration() + " ;剩余失效时间:" + oAuth2AccessToken.getExpiresIn() );
return access_token;
} }
3.以下配置是授权服务给配置的
#==================spring oauth2.0=====================================
#客户端ID
client_id=xxx
#公钥(BASE64(xx))
public_key=xxx
#私钥(BASE64(xx))
private_key=xx
#spring oauth2.0服务url
oauth_url=xxx
#获取请求code URL
request_code_url=oauth/authorize
#获取请求token或刷新token URL
request_and_refresh_token=oauth/token
#回调地址
redirect_uri=http://www.baidu.com
Spring OAuth2.0 Client官网地址:http://projects.spring.io/spring-security-oauth/docs/oauth2.html
Spring-Security-OAuth2调用微信API的更多相关文章
- Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战
一. 前言 [APP 移动端]Spring Security OAuth2 手机短信验证码模式 [微信小程序]Spring Security OAuth2 微信授权模式 [管理系统]Spring Se ...
- Spring Security整合企业微信的扫码登录,企微的API震惊到我了
本文代码: https://gitee.com/felord/spring-security-oauth2-tutorial/tree/wwopen/ 现在很多企业都接入了企业微信,作为私域社群工具, ...
- 使用Spring MVC测试Spring Security Oauth2 API
不是因为看到希望了才去坚持,而坚持了才知道没有希望. 前言 在Spring Security源码分析十一:Spring Security OAuth2整合JWT和Spring Boot 2.0 整合 ...
- 关于 Spring Security OAuth2 中 Feign 调用 Token 问题
微服务体系中,避免不了服务之间链式调用,一般使用 Feign ,由于使用 Spring Security OAuth2 全局做了安全认证,简单的一种实现方式就是在服务提供方获得 Token 再次通过 ...
- Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Axios前后端分离模式下无感刷新实现JWT续期
一. 前言 记得上一篇Spring Cloud的文章关于如何使JWT失效进行了理论结合代码实践的说明,想当然的以为那篇会是基于Spring Cloud统一认证架构系列的最终篇.但关于JWT另外还有一个 ...
- Spring Cloud实战 | 第九篇:Spring Cloud整合Spring Security OAuth2认证服务器统一认证自定义异常处理
本文完整代码下载点击 一. 前言 相信了解过我或者看过我之前的系列文章应该多少知道点我写这些文章包括创建 有来商城youlai-mall 这个项目的目的,想给那些真的想提升自己或者迷茫的人(包括自己- ...
- 【Spring Cloud & Alibaba 实战 | 总结篇】Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现微服务统一认证授权和鉴权
一. 前言 hi,大家好~ 好久没更文了,期间主要致力于项目的功能升级和问题修复中,经过一年时间的打磨,[有来]终于迎来v2.0版本,相较于v1.x版本主要完善了OAuth2认证授权.鉴权的逻辑,结合 ...
- Spring Security中实现微信网页授权
微信公众号提供了微信支付.微信优惠券.微信H5红包.微信红包封面等等促销工具来帮助我们的应用拉新保活.但是这些福利要想正确地发放到用户的手里就必须拿到用户特定的(微信应用)微信标识openid甚至是用 ...
- Spring Security Oauth2系列(一)
前言: 关于oauth2,其实是一个规范,本文重点讲解spring对他进行的实现,如果你还不清楚授权服务器,资源服务器,认证授权等基础概念,可以移步理解OAuth 2.0 - 阮一峰,这是一篇对于oa ...
- spring security oauth2 client_credentials模
spring security oauth2 client_credentials模 https://www.jianshu.com/p/1c3eea71410e 序 本文主要简单介绍一下spring ...
随机推荐
- WINCE的批处理
WINCE上没有提供象window一样的bat文件,如果需要类似功能可以借助第三方程序MortScript MortScript是一个运行于WINCE上的免费脚本解释程序,脚本文件为.mscr或.mo ...
- Leetcode_203_Remove Linked List Elements
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/45868027 Remove all elements fr ...
- asp.net 分布式探讨之Session共享问题
---恢复内容开始--- Session共享是分布式架构设计中的一大难点,尽管session共享的解决方案不少,但是.net 下的解决方案还是比较少,而且说明文档也很少. 之前尝试用memcached ...
- iOS 博客资源精选
摘要:记录一些网上非常牛的人写的博文.收藏起来. 以备日后需要时学习备用. 1:iOS中UIWebView的Javascript与Objective-C通信 http://imchao.net/201 ...
- JVM如何理解Java泛型类
//泛型代码 public class Pair<T>{ private T first=null; private T second=null; public Pair(T fir,T ...
- 多重影分身——C#中多线程的使用二(争抢共享资源)
只要服务器承受得了,我们可以开任意个线程同时工作以提高效率,然而 两个线程争抢资源可能导致数据混乱. 例如: public class MyFood { public static int Last ...
- AngularJs 学习笔记(三)依赖注入
一个对象可以通过三种方式来获取对依赖对象的控制权: 1.在内部创建依赖的对象 2.通过全局变量引用这个依赖对象 3.通过参数进行传递(在这里是通过函数参数) AngularJs通过$injector注 ...
- 无效类字符串:ProgID: Excel.Application
网上发现的方案是改注册表,其实用不着那么麻烦,找2种excel文件:xlsx和xls,把默认打开方式都换成你机器上有的程序就行,比如WPS Office的WPS 表格
- The 4 Essentials of Video Content Marketing Success
https://www.entrepreneur.com/article/243208 As videos become increasingly popular, they provide the ...
- Android 加载GIF图最佳实践
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/75578109 本文出自[赵彦军的博客] 起因 最近在项目中遇到需要在界面上显示一个 ...