单点登录(SSO)

1、单点登录(SSO)

Single Sign-On。指用户仅需一次登录,即可访问全部应用的实现,在历史中根据应用变化,SSO 也有多种实现形态。在这次接入中,是基于oauth2.0协议进行实现的。

授权协议,虽不是为了 SSO 设计,但也经常用于实现 SSO。由于 OIDC 协议基于 OAuth 2.0 协议实现,两者很多支持的模式是互通的。而对于全总的接入中心,我们是采用了Oauth2.0中的授权码模式对外开放openApi来让各个地方服务平台进行接入;Authorization Code 模式,被授权方是用户,应用通过授权码模式,可获取三方系统身份信息,并以该身份进行登录。常见的钉钉登录、微信登录等均采用授权码模式。

1.1 流程解释

在这里插入图片描述
一般来说,是先要在对应平台申请服务,然后我们的服务就会出现在对方app上,在点击该服务的时候就将对方app的登录信息自动带到我们的服务中,一般会是一个agentId参数(应用的唯一ID)和一个authorizationCode(授权码),我们够通过授权码拿到accessToken(第三方应用的授权登陆凭证/登陆令牌),再通过这个accessToken拿到用户信息,此时再进行登录把拿到的用户信息存入我们自己的数据库即可,之间肯定也会用到appKey(appKey和appSecret用于第三方应用调用接入中心接口时,对接口参数加签验签时使用)和appSecret(对接口参数加签验签时使用)

1.2 前端示例代码

//主代码
<script>
	import fw from "@/api/fw/fw";
	import {linkToClient,getBntConfigCache,getPageFilter} from "@/utils/api";
	import {setUserId,setSign,getUserId,setIdCard,getIdCard} from "@/utils/common";
	import {jsToCallApp} from "@/pages/quanZong/uniapp-callApp-1.0.0";
	
	export default{
		data(){
			return{
				name:'',
			    idCard:''
			}
		},
		methods:{
			openAppFunction(type,e){
				// uni.clearStorageSync();
				// alert(".................getIdCard():"+getIdCard("idCard"));
				if(getIdCard("idCard")!=null && getIdCard("idCard")!='') {
					this.toPage(e);
				}else{
					jsToCallApp(
						{
							type: type,
						},
						(data) => {
							if('-1'!==data && data){
								// alert(".................data2:"+data);
								data = JSON.parse(data);
								this.name = data.name;
								this.idCard = data.idCard;
								this.toPage(e);
								showContentDom.innerHTML = data;
							}
						},
					)
				}
			},
			authLogin(authorizationCode){
				this.showLoding();
				return new Promise((resolve, reject) => {
					this.$http.get('/third/client/quanZong/accessToken', {
						params:{
							authorizationCode:authorizationCode
						}
					}).then(res=>{
						this.hideLoding();
						if(res.code == 0){
							let accessToken = res.data.accessToken;
							let expire = res.data.expire;
							let refreshToken = res.data.refreshToken;
							this.$http.get('/third/client/quanZong/userInfo', {
								params:{
									accessToken:accessToken
								}
							}).then(res=>{
								if(res.code == 0){
									this.$http.post('/third/client/quanZong/authLogin', {
										mobile:res.data.mobile,
										nickname:res.data.name,
										username:this.name,
										idCard:this.idCard,
										gender:res.data.gender,
										avatarUrl:res.data.avatarUrl,
										userType:res.data.userType,
										did:res.data.did,
										userId:res.data.userId
									}).then(res=>{
										this.hideLoding();
										if(res.code == 200){
											let r = res.data;
											setUserId(r.id);
											setSign(r.signStr);
											setIdCard(r.idCard);
											resolve(true);
										} else{
											this.toast(res.msg);
											resolve(false);
										}
									})
								} else{
									this.toast(res.msg);
									resolve(false);
								}
							})
						} else{
							this.toast(res.msg);
							resolve(false);
						}
					})
				})
			},
			async toPage(e){
				if(!e.authorizationCode || !e.state){
					uni.showToast({
						title:"授权失败,请重新进入",
						icon:"none"
					})
					/* setTimeout(function(){
						window.history.back();
					},2000) */
					return;
				}
				let res= await this.authLogin(e.authorizationCode);
				if(res){
					let url="";
					//政策咨询
					if(e.state==1){
						// url="/pages/jingtong/policy-advisory?id=1";
						url="/pages/want-help/seek-help?id=1";
					}else if(e.state==2){
						//法律援助
						// url="/pages/jingtong/policy-advisory?id=2";
						linkToClient("https://ff.bjzgh12351.org/ff/#/","法律服务",'client');
						return;
						
					}
					else if(e.state==3){
						//互助保障
						// url="/pages/jingtong/policy-advisory?id=3";
						url="/pages/mutual-guarantee/mutual-guarantee";
					}
					else if(e.state==4){
						//困难帮扶
						// url="/pages/jingtong/policy-advisory?id=4";
						url="/pages/want-help/seek-help?id=4";
					}
					else if(e.state==5){
						//职业介绍
						// url="/pages/jingtong/policy-advisory?id=5";
						url="/pages/want-help/seek-help?id=5";
					}
					else if(e.state==6){
						//我要入会
						url="/pages/jingtong/application-form";
					}
					else if(e.state==7){
						//就业招聘
						url="/pages/jingtong/professional-integrity";
					}
					else if(e.state==8){
						//参保活动查询
						url="/pages/jingtong/activity-process";
					}
					else if(e.state==9){
						//保障给付查询
						url="/pages/jingtong/guarantee-payment";
					}
					else if(e.state==10){
						//个人理赔申报
						url="/pages/jingtong/personal-claims";
					}
					else if(e.state==11){
						//创业贷款申请
						url="/pages/jingtong/petty-loan";
						
					}
					else if(e.state==12){
						//保障活动资讯
						url="/pages/jingtong/mutual-guarantee";
					}
					else if(e.state==13){
						//驿站
						url="/pages/jingtong/site-map";
						
					}
					else if(e.state==14){
						//法律服务
						linkToClient("https://ff.bjzgh12351.org/ff/#/","法律服务",'client');
						return;
					}
					else if(e.state==15){
						//心理关爱
						linkToClient("https://bjzgxl.pemcloud.cn/index.php/M3djk/member/getCode","心理关爱",'client');
						return;
					}
					else if(e.state==16){
						//电子书屋
						linkToClient("https://mo.591adb.cn/bjszgh.html","电子书屋",'client');
						return;
					}else if(e.state==17){
						//我要求助
						url="/pages/want-help/seek-help";
					}
					
					uni.reLaunch({
					    url: url
					})
				}
			}
		},
		onLoad(e) {
			var that = this;
			setTimeout(function(){
				that.openAppFunction('openKbToAuth',e);
			},300);
			// this.toPage(e);
		},
		
	}
</script>

//JS
// #ifdef H5
function initUserPlugin() {
	// 这里根据移动端原生的 userAgent 来判断当前是 Android 还是 ios
	
	// alert('>>>>>>>>>进来1>>>>>>>>')
	const u = navigator.userAgent
	// Android终端
	const isAndroid = u.startsWith("QzApp") && u.indexOf('Android') > -1 || u.indexOf('Adr') > -1
	// IOS 终端
	const isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)

	/**
	 * 配合 IOS 使用时的初始化方法
	 */
	const iosFunction = (callback) => {
		if (window.WebViewJavascriptBridge) { return callback(window.WebViewJavascriptBridge) }
		if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback) }
		window.WVJBCallbacks = [callback]
		var WVJBIframe = document.createElement('iframe')
		WVJBIframe.style.display = 'none'
		WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__'
		document.documentElement.appendChild(WVJBIframe)
		setTimeout(function () {
			document.documentElement.removeChild(WVJBIframe)
		}, 0)
	}

	/**
	 * 配合 Android 使用时的初始化方法
	 */
	const androidFunction = (callback) => {
		if (window.WebViewJavascriptBridge) {
			callback(window.WebViewJavascriptBridge)
		} else {
			document.addEventListener('WebViewJavascriptBridgeReady', function () {
				callback(window.WebViewJavascriptBridge)
			}, false)
		}
	}
	window.setupWebViewJavascriptBridge = isAndroid ? androidFunction : isIOS ? iosFunction : androidFunction
	window.setupWebViewJavascriptBridge(function (bridge) {

	})
}
initUserPlugin()
// #endif

// js注册方法
export function appCallJsRegister(name, callBack) {
	// initUserPlugin()
	window.setupWebViewJavascriptBridge(
		bridge => {
			bridge.registerHandler(name, callBack)
		}
	)
}

// js传递数据给java
export function jsToCallApp(data, callBack) {
	// initUserPlugin()
	if (window.WebViewJavascriptBridge) {
		window.WebViewJavascriptBridge.callHandler(
			'h5CallApp',
			data,
			function (responseData) {
				// 回传的数据
				callBack && callBack(responseData)
			}
		)
	} else {
		callBack && callBack('-1')
	}
}

export function toShowBack(isShow) {
	jsToCallApp({
		type: 'showLeftBack', // 需要操作的事件类型
		isShow: isShow,
	},
		(backData) => {
			console.log(backData)
		},)
}

1.3 后端示例代码

①Controller层
package com.yuqiaotech.third.feign.controller.quanzong;

import com.alibaba.fastjson.JSONObject;
import com.gbs.saas.sdk.oauth2.authentication.client.ISsoAuthenClient;
import com.gbs.saas.sdk.oauth2.authentication.client.dto.request.AccessTokenRefreshRequest;
import com.gbs.saas.sdk.oauth2.authentication.client.dto.request.AccessTokenRequest;
import com.gbs.saas.sdk.oauth2.authentication.client.dto.request.UserInfoQueryRequest;
import com.gbs.saas.sdk.oauth2.authentication.client.dto.response.AccessTokenResponse;
import com.gbs.saas.sdk.oauth2.authentication.client.dto.response.UserInfoQueryResponse;
import com.gbs.saas.sdk.oauth2.authentication.common.model.Result;
import com.yuqiaotech.base.BaseController;
import com.yuqiaotech.domain.UserInfo;
import com.yuqiaotech.estivate.aop.DataSource;
import com.yuqiaotech.feign.third.model.QuanZongUserInfoDto;
import com.yuqiaotech.model.R;
import com.yuqiaotech.third.feign.service.quanzong.QuanZongThirdFeign;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

@RestController
@RequestMapping("/client/quanZong")
@DataSource
public class QuanZongController extends BaseController {

    @Autowired
    private ISsoAuthenClient ssoAuthenClient;

    @Autowired
    private QuanZongThirdFeign quanZongThirdFeign;

    @PostMapping("/authLogin")
    public R authLogin(@RequestBody QuanZongUserInfoDto quanZongUserInfoDto){
        UserInfo me = getCurrentUserInfox();
        R r = new R();
        try {
            if(me==null){
                r= quanZongThirdFeign.authLogin(quanZongUserInfoDto);
            }else{
                JSONObject json = new JSONObject();
                Long userInfoId = me.getId();
                json.put("id", userInfoId);
                json.put("userType", me.getUserType());
                String pwd = me.getPassword();
                if(pwd == null || "".equals(pwd))pwd = me.getId()+"";
                String signature2 = DigestUtils.md5Hex(pwd);
                signature2 = DigestUtils.md5Hex(signature2);
                json.put("signStr",signature2);
                String idCard = me.getIdCard();
                if(idCard == null || "".equals(idCard)){
                    json.put("idCard",null);
                    r.setCode(250);
                    r.setMsg("身份信息未录入,请稍后进入重新授权!");
                    r.setData(json);
                    return r;
                }else {
                    String idCard2 = DigestUtils.md5Hex(idCard);
                    idCard2 = DigestUtils.md5Hex(idCard2);
                    json.put("idCard",idCard2);
                }
                r.setCode(200);
                r.setMsg("登录成功");
                r.setData(json);
            }

        } catch (Exception e) {
            e.printStackTrace();
            r.setCode(500);
            r.setMsg("服务异常");
        }
        return r;
    }

    /**
     * 授权码交换accessToken
     * @param request
     * @param authorizationCode
     * @return
     */
    @GetMapping("/accessToken")
    public Result<AccessTokenResponse> getAccessToken(HttpServletRequest request, String authorizationCode){
        AccessTokenRequest accessTokenRequest=new AccessTokenRequest(authorizationCode);
        accessTokenRequest.setRequestId(UUID.randomUUID().toString());
        Result<AccessTokenResponse> result=this.ssoAuthenClient.accessToken(accessTokenRequest);
        return result;
    }

    /**
     * 获取登陆用户信息
     * @param request
     * @param accessToken
     * @return
     */
    @GetMapping("/userInfo")
    public Result<UserInfoQueryResponse> getUserInfo(HttpServletRequest request, String accessToken){
        UserInfoQueryRequest userQuery=new UserInfoQueryRequest();
        userQuery.setAccessToken(accessToken);
//    userQuery.setIncludeOrganization(false);
//    userQuery.setIncludeRole(false);
        Result<UserInfoQueryResponse> result=this.ssoAuthenClient.getUserInfo(userQuery);
        return result;
    }

    /**
     * 刷新accessToken
     * @param request
     * @param refreshToken
     * @return
     */
    @GetMapping("/refreshToken")
    public Result<AccessTokenResponse> refreshToken(HttpServletRequest request,String refreshToken){
        AccessTokenRefreshRequest accessTokenRefreshRequest=new AccessTokenRefreshRequest(refreshToken);
        accessTokenRefreshRequest.setRefreshToken(refreshToken);
        Result<AccessTokenResponse> result=this.ssoAuthenClient.refreshToken(accessTokenRefreshRequest);
        return result;
    }


}

②Service层
package com.yuqiaotech.third.feign.service.quanzong.impl;

import com.alibaba.fastjson.JSONObject;
import com.gbs.saas.sdk.oauth2.authentication.common.utils.SsoEncryptUtil;
import com.yuqiaotech.domain.UserInfo;
import com.yuqiaotech.feign.third.model.QuanZongUserInfoDto;
import com.yuqiaotech.model.R;
import com.yuqiaotech.repository.BaseRepository;
import com.yuqiaotech.service.UserInfoBaseService;
import com.yuqiaotech.third.feign.service.quanzong.QuanZongThirdFeign;
import com.yuqiaotech.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class QuanZongThirdFeignService implements QuanZongThirdFeign {

    @Value("${sso.appSecret}")
    private String appSecret;

    @Autowired
    private BaseRepository<UserInfo, Long> userInfoLongBaseRepository;

    @Autowired
    private UserInfoBaseService userInfoBaseService;

    @Autowired
    RedisUtils redisUtils;

    @Override
    public R authLogin(QuanZongUserInfoDto quanZongUserInfoDto) {
        log.info("appSecret-------------",appSecret);
        JSONObject json = new JSONObject();
        //解密手机号
        String phone = SsoEncryptUtil.aesDecryptHex(appSecret,quanZongUserInfoDto.getMobile());
        //拿到身份证信息
        String idCard = quanZongUserInfoDto.getIdCard();
        UserInfo userInfo=userInfoLongBaseRepository.findUniqueBy("mobile",phone,UserInfo.class);
        //用户可以通过手机号查到且身份证号一致 就说明是同一个用户
        if(userInfo!=null && userInfo.getIdCard().equals(quanZongUserInfoDto.getIdCard())){
            //身份证号
            userInfo.setIdCard(idCard);
            String idCard2 = DigestUtils.md5Hex(idCard);
            idCard2 = DigestUtils.md5Hex(idCard2);
            json.put("idCard",idCard2);
        }else {
            userInfo = new UserInfo();
            //手机号 解密后存入
            userInfo.setMobile(phone);
            //昵称
            userInfo.setNickName(quanZongUserInfoDto.getNickname());
            //名称
            userInfo.setUsername(quanZongUserInfoDto.getUsername());
            //性别
            userInfo.setSex(quanZongUserInfoDto.getGender());
            //头像
            userInfo.setWxLogo(quanZongUserInfoDto.getAvatarUrl());
            //用户类型
            userInfo.setSubUserType("全总");
//        //用IdCard来存放did信息
//        userInfo.setIdCard(quanZongUserInfoDto.getDid());
//        //用CId来存放userId
//        userInfo.setCId(quanZongUserInfoDto.getUserId());
            if(idCard == null || "".equals(idCard)){
                json.put("idCard",null);
                return R.tips(json, "身份信息未录入,请稍后进入重新授权!");
            }else {
                //身份证号
                userInfo.setIdCard(idCard);
                String idCard2 = DigestUtils.md5Hex(idCard);
                idCard2 = DigestUtils.md5Hex(idCard2);
                json.put("idCard",idCard2);
            }
            userInfoLongBaseRepository.save(userInfo);
        }

        userInfoBaseService.toRedis(userInfo);
        Long userInfoId = userInfo.getId();
        json.put("id", userInfoId);
        json.put("userType", userInfo.getUserType());
        String pwd = userInfo.getPassword();
        if(pwd == null || "".equals(pwd))pwd = userInfo.getId()+"";
        String signature2 = DigestUtils.md5Hex(pwd);
        signature2 = DigestUtils.md5Hex(signature2);
        json.put("signStr",signature2);
        return R.ok(json, "登录成功");
    }
}

1.4 引入第三方jar包

在resources中新建一个lib放入你需要引入的jar包
在这里插入图片描述
然后要在pom.xml中进行配置,因为我这边有几个jar包所以要配置多次
在这里插入图片描述
最后配置打jar/war包时,打入自己的jar包
在这里插入图片描述
如果要打war包需要下面这套代码

			<groupId>org.apache.maven.plugins</groupId>
			<artifactId>maven-war-plugin</artifactId>
			<version>3.2.2</version>
			<configuration>
				<webResources>
					<resource>
						<!-- 指向的是包含你所有要用jar包的目录 -->
						<directory>${project.basedir}/src/main/resources/lib</directory>
						<!-- 编译后要把这些jar包复制到的位置 -->
						<targetPath>WEB-INF/lib</targetPath>
					</resource>
				</webResources>
			</configuration>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值