由于公司需要cas集成微信。但是在网上没有找到相应的示例。然后我就跑到官网上去找了一下CAS怎么集成OAuth的。这是基于pac4j-oauth-1.4.1.jar包org.pac4j.oauth.client包中用于oauth 2.0协议与CAS集成类的对应与的。下面是对应的Client,毕竟是人家外国人的jar。没有微信的,那就只有自己写咯。

下面的官网加上我自己的改动。

1、在cas-server-webapp中的pom.xml中加入以下dependency用于支持oauth.

<dependency>  <groupId>org.jasig.cas</groupId>  <artifactId>cas-server-support-pac4j</artifactId>  <version>${cas.version}</version>
</dependency>  

2、配置传递属性

在CAS service端为了把属性传递到CAS client端,我们需要在deployerConfigContext.xml文件中配置以下信息:

<bean id="serviceRegistryDao" class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">  <property name="registeredServices">  <list>  <bean class="org.jasig.cas.services.RegisteredServiceImpl">  <property name="id" value="0" />  <property name="name" value="HTTP" />  <property name="description" value="Only Allows HTTP Urls" />  <property name="serviceId" value="http://**" />  <property name="evaluationOrder" value="10000001" />  <property name="allowedAttributes">  <list>  <!-- weixin -->  <value>openid</value>  <value>nickname</value>  <value>and so on</value>  ... 

3、在cas-server-support-pac4j项目的pom.xml增加必需的pac4j-* libraries

<dependency>  <groupId>org.pac4j</groupId>  <artifactId>pac4j-oauth</artifactId>  <version>${pac4j.version}</version>
</dependency>  

4、修改applicationContext.xml

在applicationContext.xml添加对应的oauth的clients。并把clients增加到对应的org.pac4j.core.client.Clients中,同样也是在applicationContext.xml

<bean id="clients" class="org.pac4j.core.client.Clients">  <property name="callbackUrl" value="https://login.nmall.com/cas/login" />  <property name="clients">  <list>  <ref bean="weiXin" />  <ref bean="qq" />  </list>  </property>
</bean>
<bean id="weiXin" class="org.jasig.cas.support.pac4j.plugin.weixin.WeiXinClient">  <property name="key" value="yourkey" />  <property name="secret" value="yousecret" />
</bean>
<bean id="qq" class="org.jasig.cas.support.pac4j.plugin.qq.QqClient">  <property name="key" value="yourkey" />  <property name="secret" value="yousecret" />
</bean>  

5、修改login-webflow.xml,增加oauth用户验证逻辑

把处理oauth的client action添加到webflow中在login-webflow.xml中,这clientAction添加在webflow的最前面.它的任务是微信oauth用户验证的callback的调用.

<action-state id="clientAction">  <evaluate expression="clientAction" />  <transition on="success" to="sendTicketGrantingTicket" />  <transition on="error" to="ticketGrantingTicketCheck" />  <transition on="stop" to="stopWebflow" />
</action-state>
<view-state id="stopWebflow" />  

clientAction这个bean必须定义在cas-servlet.xml,并且需要注入clients.

<bean id="clientAction" class="org.jasig.cas.support.pac4j.web.flow.ClientAction">  <constructor-arg index="0" ref="centralAuthenticationService"/>  <constructor-arg index="1" ref="clients"/>
</bean  

clientAction需要用到的centralAuthenticationService这个bean已经之前的用户验证已经配置好了。

6、增加用户验证的handler与数据入口.

<bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">  <constructor-arg>  <map>     <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />  <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />  <entry key-ref="customerDBAuthHandler" value-ref="customerDBPrincipalResolver" />  </map>  </constructor-arg>  <property name="authenticationMetaDataPopulators">  <util:list>  <bean class="org.jasig.cas.support.pac4j.authentication.ClientAuthenticationMetaDataPopulator" />  </util:list>  </property>  <property name="authenticationPolicy">  <bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />  </property>
</bean>
<bean id="primaryAuthenticationHandler" class="org.jasig.cas.support.pac4j.authentication.handler.support.ClientAuthenticationHandler">  <constructor-arg index="0" ref="clients"/>
</bean>
<bean id="primaryPrincipalResolver" class="org.jasig.cas.support.pac4j.plugin.common.OauthPersonDirectoryPrincipalResolver" / >

这个OauthPersonDirectoryPrincipalResolver类是需要自己重写的,此类用于oauth微信返回的用户信息处理返回给cas client端。

package org.jasig.cas.support.pac4j.plugin.common;  import java.util.Map;  import org.jasig.cas.authentication.Credential;
import org.jasig.cas.authentication.principal.Principal;
import org.jasig.cas.authentication.principal.PrincipalResolver;
import org.jasig.cas.authentication.principal.SimplePrincipal;
import org.jasig.cas.support.pac4j.authentication.principal.ClientCredential;
import org.pac4j.core.profile.UserProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;  public class OauthPersonDirectoryPrincipalResolver implements PrincipalResolver {  /** Log instance. */  protected final Logger logger = LoggerFactory.getLogger(this.getClass());  private boolean returnNullIfNoAttributes = false;  public void setReturnNullIfNoAttributes(final boolean returnNullIfNoAttributes) {  this.returnNullIfNoAttributes = returnNullIfNoAttributes;  }  @Override  public Principal resolve(Credential credential) {  logger.debug("Attempting to resolve a principal...");  if (credential instanceof ClientCredential){  // do nothing  } else {  throw new RuntimeException("用户数据转换异常!");  }  ClientCredential oauthCredential = (ClientCredential) credential;  String principalId = oauthCredential.getUserProfile().getId();  if (principalId == null) {  logger.debug("Got null for extracted principal ID; returning null.");  return null;  }  logger.debug("Creating SimplePrincipal for [{}]", principalId);  UserProfile userProfile = oauthCredential.getUserProfile();  final Map<String, Object> attributes = userProfile.getAttributes();  if (attributes == null & !this.returnNullIfNoAttributes) {  return new SimplePrincipal(principalId);  }  if (attributes == null) {  return null;  }  return new SimplePrincipal(principalId, attributes);  }  @Override  public boolean supports(Credential credential) {  return true;  }  }  

7、最后为了添加用户验证在远程调用

最后为了添加用户验证在远程调用,也就是微信。必须添加以下链接到登录页面casLoginView.jsp(ClientNameUrl这个属性是被ClientAction自动创建).也就是你自定义的Client类名加上Url.如我创建的类为WeixinClient则对应的link名为WeixinClientUrl。

<a href="${WeiXinClientUrl}">Authenticate with Wechat</a> <br />
<br />
<a href="${QqClientUrl}">Authenticate with QQ</a><br />  

8、修改cas-server-support-pac4j(重点)

以上都是准备工作,下面才是真正的工作。因为在pac4j-oauth-1.4.1.jar这个包里面没有对weixin的相关支持所有只有自己手动修改了。以下的类是基于pac4j-oauth-1.4.1.jar包org.pac4j.oauth.client包中用于oauth 2.0协议与CAS集成类的对应与的。项目结构如下图所示:

1)用于处理CAS与微信的OAUTH通信。

package org.jasig.cas.support.pac4j.plugin.weixin;  import org.pac4j.core.client.BaseClient;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.HttpCommunicationException;
import org.pac4j.oauth.client.BaseOAuth20Client;
import org.pac4j.oauth.credentials.OAuthCredentials;
import org.pac4j.oauth.profile.JsonHelper;
import org.scribe.model.OAuthConfig;
import org.scribe.model.ProxyOAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.SignatureType;
import org.scribe.model.Token;
import org.springframework.beans.factory.annotation.Autowired;  import com.fasterxml.jackson.databind.JsonNode;
import com.lm.b2c.core.enumerate.LoginKeyType;
import com.lm.b2c.core.lang.Pair;
import com.lm.b2c.user.manager.customer.api.CustomerManager;
import com.lm.b2c.user.manager.customer.vo.CombinedAccountVO;  /** * 此类用于处理CAS与微信的OAUTH通信 * @author b2c021 * */
public class WeiXinClient extends BaseOAuth20Client<WeiXinProfile> {  private final static WeiXinAttributesDefinition WEI_XIN_ATTRIBUTES = new WeiXinAttributesDefinition();  @Autowired  private CustomerManager customerManager;  public WeiXinClient(){}  public WeiXinClient(final String key, final String secret){  setKey(key);  setSecret(secret);  }  @Override  protected BaseClient<OAuthCredentials, WeiXinProfile> newClient() {  // TODO  WeiXinClient newClient = new WeiXinClient();  return newClient;  }  @Override  protected void internalInit() {  // TODO  super.internalInit();  WeiXinApi20 api = new WeiXinApi20();  this.service = new WeiXinOAuth20ServiceImpl(api, new OAuthConfig(this.key, this.secret, this.callbackUrl,SignatureType.Header, null, null),  this.connectTimeout, this.readTimeout, this.proxyHost,this.proxyPort);  }  @Override  protected String getProfileUrl() {  // TODO Auto-generated method stub  // eg.google2Client:return "https://www.googleapis.com/oauth2/v2/userinfo";  return "https://api.weixin.qq.com/sns/userinfo";  }  @Override  protected WeiXinProfile extractUserProfile(String body) {  WeiXinProfile weiXinProfile = new WeiXinProfile();  final JsonNode json = JsonHelper.getFirstNode(body);  if (null != json) {  for(final String attribute : WEI_XIN_ATTRIBUTES.getPrincipalAttributes()){  weiXinProfile.addAttribute(attribute, JsonHelper.get(json, attribute));  }  /** 绑定账号到系统 */  String openId = (String) weiXinProfile.getAttributes().get("openid");  String nickName = (String) weiXinProfile.getAttributes().get("nickname");  CombinedAccountVO combinedAccount = generateAccount(openId, LoginKeyType.WECHAT, nickName);  Pair<Long,String> suidAndLoginName = customerManager.bindAccount(combinedAccount);  weiXinProfile.addAttribute("suid", suidAndLoginName.getFirst());  weiXinProfile.setId(suidAndLoginName.getSecond());  }  return weiXinProfile;  }  /** * 需求state元素 */  @Override  protected boolean requiresStateParameter() {  return false;  }  @Override // Cancelled 取消  protected boolean hasBeenCancelled(WebContext context) {  return false;  }  @Override  protected String sendRequestForData(final Token accessToken, final String dataUrl) {  logger.debug("accessToken : {} / dataUrl : {}", accessToken, dataUrl);  final long t0 = System.currentTimeMillis();  final ProxyOAuthRequest request = createProxyRequest(dataUrl);  this.service.signRequest(accessToken, request);  final Response response = request.send();  final int code = response.getCode();  final String body = response.getBody();  final long t1 = System.currentTimeMillis();  logger.debug("Request took : " + (t1 - t0) + " ms for : " + dataUrl);  logger.debug("response code : {} / response body : {}", code, body);  if (code != 200) {  logger.error("Failed to get data, code : " + code + " / body : " + body);  throw new HttpCommunicationException(code, body);  }  return body;  }  private CombinedAccountVO generateAccount(String openId,LoginKeyType keyType, String nickName){  CombinedAccountVO vo = new CombinedAccountVO();  vo.setLoginKey(openId);  vo.setKeyType(keyType);  vo.setNickName(nickName);  return vo;  }
}  

2)、用于定义获取微信返回的CODE与ACCESSTOKEN

package org.jasig.cas.support.pac4j.plugin.weixin;  import org.scribe.builder.api.DefaultApi20;
import org.scribe.extractors.AccessTokenExtractor;
import org.scribe.extractors.JsonTokenExtractor;
import org.scribe.model.OAuthConfig;
import org.scribe.model.Verb;
import org.scribe.utils.OAuthEncoder;  /** * 用于定义获取微信返回的CODE与ACCESS_TOKEN * @author b2c021 * */
public class WeiXinApi20 extends DefaultApi20 {  private static final String WEIXIN_AUTHORIZE_URL = "https://open.weixin.qq.com/connect/qrconnect?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_login#wechat_redirect";  @Override  public AccessTokenExtractor getAccessTokenExtractor()  {  return new JsonTokenExtractor();  }  @Override  public Verb getAccessTokenVerb()  {  return Verb.POST;  }  @Override  public String getAccessTokenEndpoint() {  return "https://api.weixin.qq.com/sns/oauth2/access_token";  }  @Override  public String getAuthorizationUrl(OAuthConfig config) {  return String.format(WEIXIN_AUTHORIZE_URL, config.getApiKey(), OAuthEncoder.encode(config.getCallback()));  }  }  

3)、用于接收微信返回的用户信息

package org.jasig.cas.support.pac4j.plugin.weixin;  import org.pac4j.core.profile.converter.Converters;
import org.pac4j.oauth.profile.OAuthAttributesDefinition;  /** * 用于接收微信返回的用户信息 * @author b2c021 * */
public class WeiXinAttributesDefinition extends OAuthAttributesDefinition {  public static final String OPEN_ID = "openid";  public static final String NICK_NAME = "nickname";  /** 用户性别,1为男性,2为女性 */  public static final String SEX = "sex";  public static final String COUNTRY = "country";  public static final String PROVINCE = "province";  public static final String CITY = "city";  public static final String HEAD_IMG_URL = "headimgurl";  public static final String PRIVILEGE = "privilege";  public static final String UNION_ID = "unionid";  // appended  public static final String APP_NAME = "appName";  public static final String SUID = "suid";  public WeiXinAttributesDefinition(){  addAttribute(OPEN_ID, Converters.stringConverter);  addAttribute(NICK_NAME, Converters.stringConverter);  addAttribute(SEX, Converters.integerConverter);  addAttribute(COUNTRY, Converters.stringConverter);  addAttribute(PROVINCE, Converters.stringConverter);  addAttribute(CITY, Converters.stringConverter);  addAttribute(HEAD_IMG_URL, Converters.stringConverter);  addAttribute(UNION_ID, Converters.stringConverter);  addAttribute(APP_NAME, Converters.stringConverter);  addAttribute(SUID, Converters.longConverter);  }
}  

4)、用于获取微信返回的ACCESS_TOKEN

package org.jasig.cas.support.pac4j.plugin.weixin;  import java.util.regex.Matcher;
import java.util.regex.Pattern;  import org.scribe.exceptions.OAuthException;
import org.scribe.model.Token;
import org.scribe.utils.Preconditions;  /** * 用于获取微信返回的ACCESS_TOKEN * @author b2c021 * */
public class WeiXinJsonTokenExtractor {  private Pattern accessTokenPattern = Pattern.compile("\"access_token\":\\s*\"(\\S*?)\"");  public Token extract(String response){  Preconditions.checkEmptyString(response, "Cannot extract a token from a null or empty String");  Matcher matcher = accessTokenPattern.matcher(response);  if(matcher.find()){  return new Token(matcher.group(1), "", response);  }  else{  throw new OAuthException("Cannot extract an acces token. Response was: " + response);  }  }  }  

5)、用于添加获取ACCESS_TOKEN与用户信息添加参数并请求微信

package org.jasig.cas.support.pac4j.plugin.weixin;  import java.util.regex.Matcher;
import java.util.regex.Pattern;  import org.scribe.builder.api.DefaultApi20;
import org.scribe.exceptions.OAuthException;
import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthConstants;
import org.scribe.model.OAuthRequest;
import org.scribe.model.ProxyOAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.ProxyOAuth20ServiceImpl;  /** * 用于添加获取ACCESS_TOKEN与用户信息添加参数并请求微信 * @author b2c021 * */
public class WeiXinOAuth20ServiceImpl extends ProxyOAuth20ServiceImpl {  private static Pattern openIdPattern = Pattern.compile("\"openid\":\\s*\"(\\S*?)\"");  public WeiXinOAuth20ServiceImpl(DefaultApi20 api, OAuthConfig config, int connectTimeout, int readTimeout, String proxyHost, int proxyPort) {  super(api, config, connectTimeout, readTimeout, proxyHost, proxyPort);  }  /** * 获取account_token的http请求参数添加 */  @Override  public Token getAccessToken(final Token requestToken, final Verifier verifier) {  final OAuthRequest request = new ProxyOAuthRequest(this.api.getAccessTokenVerb(),  this.api.getAccessTokenEndpoint(), this.connectTimeout,  this.readTimeout, this.proxyHost, this.proxyPort);  request.addBodyParameter("appid", this.config.getApiKey());  request.addBodyParameter("secret", this.config.getApiSecret());  request.addBodyParameter(OAuthConstants.CODE, verifier.getValue());  request.addBodyParameter(OAuthConstants.REDIRECT_URI, this.config.getCallback());  request.addBodyParameter("grant_type", "authorization_code");  final Response response = request.send();  return this.api.getAccessTokenExtractor().extract(response.getBody());  }  @Override  public void signRequest(final Token accessToken, final OAuthRequest request) {  request.addQuerystringParameter(OAuthConstants.ACCESS_TOKEN, accessToken.getToken());  String response = accessToken.getRawResponse();  Matcher matcher = openIdPattern.matcher(response);  if(matcher.find()){  request.addQuerystringParameter("openid", matcher.group(1));  }  else{  throw new OAuthException("微信接口返回数据miss openid: " + response);  }  }
}  

6)、用于添加返回用户信息

package org.jasig.cas.support.pac4j.plugin.weixin;  import org.pac4j.core.profile.AttributesDefinition;
import org.pac4j.oauth.profile.OAuth20Profile;  /** * 用于添加返回用户信息 * @author b2c021 * */
public class WeiXinProfile extends OAuth20Profile {  private static final long serialVersionUID = -7969484323692570444L;  @Override  protected AttributesDefinition getAttributesDefinition() {  return new WeiXinAttributesDefinition();  }  }  

引用地址:http://jasig.github.io/cas/4.0.x/integration/Delegate-Authentication.html

CAS SSO 4.0.x 集成OAuth(微信登陆示例)相关推荐

  1. CAS SSO 4.0.x 用户数据库验证

    转载地址: CAS 4.0 单点登录教程 1.概述 单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录 ...

  2. CAS SSO 4.0.x 增加验证码

    这一篇主要是讲解怎么在登录页上添加验证码功能,默认的登录页是只有用户名与密码功能.其他我觉得加验证码没什么用,因为现在我部门做的系统主要是放在内网里,外网是不能访问的.登录页的验证码主要是为了防止进账 ...

  3. 单点登录(shiro与Spring Security OAuth 2.0的集成)

    单点登录(shiro与Spring Security OAuth 2.0的集成) shiro项目采用ruoyi,OAuth采用pig 若依:https://gitee.com/y_project/Ru ...

  4. OAuth 2.0设计(以微信登录为例)

    在实际应用开发中,我们常常需要使用微信作为应用的登陆方式,不同于手Q登陆使用传统的ptlogin,微信登陆采用了OAuth 2.0的验证方式.本文将以微信登录为案例,具体分析介绍所采用的OAuth 2 ...

  5. CAS单点登录-第三方登录[QQ、微信、CSDN、GitHub](十四)

    CAS单点登录-第三方登录[QQ.微信.CSDN.GitHub](十四) 注: 目前博文使用cas版本为5.1.5,由于5.2.x与5.1.x构建模式有差异,所以部分配置会有些偏差. 本章内容 简答介 ...

  6. CAS+SSO原理浅谈

    http://www.cnblogs.com/yonsin/archive/2009/08/29/1556423.html SSO 是一个非常大的主题,我对这个主题有着深深的感受,自从广州 UserG ...

  7. 单点登录之CAS SSO从入门到精通(第三天)

    开场白 各位新年好,上海的新年好冷,冷到我手发抖. 做好准备全身心投入到新的学习和工作中去了吗?因为今天开始的教程很"变态"啊,我们要完成下面几件事: 自定义CAS SSO登录界面 ...

  8. 移动共享开发(二)各平台SSO(免登录)配置 微信和微信朋友圈、QQ、QQ空间、新浪微博、腾讯微博、人人

    SSO名词解释 : SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. 例如用户已经登录新浪微博客户端,使用SSO授权 ...

  9. CAS SSO 单点登录 【完整版】

    什么是单点登录?什么是SSO? SSO就是单点登录!!! SSO即Single Sign On. 可是为什么我们要单点登录呢?为什么不能把所有的系统做成一个war包里呢? 道理很简单啊,如果这个银行这 ...

最新文章

  1. oracle创建数据库、表空间、用户并授权
  2. matconvnet中使用fastrcnn遇到的问题
  3. python中if __name__ == '__main__'功能的解析
  4. KMP算法 java版本
  5. Linux网络编程服务器模型选择之并发服务器(上)
  6. 一起学习C语言:初谈指针(三)
  7. python的numpy库结构_NumPy构成了数据科学领域中许多Python库的基础。
  8. PTA:6-8 数组元素的区间删除 (20 分)
  9. Hadoop面向行和面向列格式详解
  10. 艾宾浩斯遗忘曲线.pdf百日计划表.pdf考研时间计划表.pdf每日打卡.pdf每日复习计划表.pdf详细日计划.pdf月计划表.pdf周计划.pdf
  11. 宋佳乐和郭晓婷天津之眼观景照片
  12. Codeforces--1311A--Duff and Weight Lifting
  13. jxt解析上传的xls文件
  14. AR5B22网卡折腾记录
  15. 想要Linux上云?如何实现Linux工作流上云部署
  16. 网站增加百度收录最有效的方法!!!!!!
  17. 淘宝旺旺号转userid 和 uid 的接口方法
  18. Win10重装的方法?一键重装Win10的图文版教程
  19. unity3d:ugui 长按按钮
  20. 什么事长连接 短连接

热门文章

  1. 科技大佬们的编程水平怎么样?
  2. python搜索关键词自动提交_Python多线程采集百度相关搜索关键词工具带exe程序!...
  3. R语言gganimate包创建散点图动画图(gif)、transition_states函数根据分组变量创建动图、shadow_wake函数配置动画的渐变效果(gradual falloff)拖尾效应
  4. Oracle11g(RAC)补丁安装(31718723,31668908)
  5. 【imessage苹果群发家庭推】Development Provisioning Profile署名
  6. java web报表,jasperReport使用简介
  7. Debian 中 BCM43142 蓝牙无法使用问题
  8. idea:properties in parent definition are prohibited提示报错
  9. BZOJ 4296 PA2015 Mistrzostwa
  10. web前端(2)—— 前端技术介绍