NCC集成统一身份认证实现单点登录

866 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

1. SSO统一登录Oauth2.0简化模式对接

1.1 实现效果

用户访问ncc系统时,有两种登录方式,一是输入用户密码登录,二是通过统一身份认证系统登录时。若统一身份认证系统未登录,则跳转到统一身份认证系统进行登录后,单点登录到ncc系统;若已登录,直接单点登录到ncc系统。

1.2 业务流程

图片1.png

1.3 时序图

image.png

2. 单点登录到ncc

2.1 工作流程

a. 客户端向服务端发起登陆NCC请求;
b. 向NCC服务器注册校验用户登陆和上下文信息;
c. 如果校验成功NCC服务器响应给客户服务器token信息;
d. 客户服务器将token响应给客户端;
f. 客户端收到token后拼接请求ncc节点的url信息;
e. NCC收到请求并验证token是否合法,如果合法,则重定向到客户端请求的节点页面。

image.png

2.2 具体配置流程

2.2.1 NCC端设置

在NCC的系统注册表sm_oauth_security注册第三方系统

2.2.1.1 表中各字段含义

  • CLIENT_ID:第三方系统编码,必需项
  • CLIENT_NAME: 第三方系统名称,非必需
  • CLIENT_SECURITY: 第三方系统和NCC共同维护的秘钥对
  • PK_OAUTH_SECURITY: 主键
  • CLIENT_URL: 第三方系统的url (供NCC集成访问第三方系统使用,本环节不需要)
  • CLIENT_AUTHCLASS: 登录第三方系统授权类 (供NCC集成访问第三方系统使用,本环节不需要)
  • PK_GROUP:非本环节使用,设置为空

2.2.1.2 注册sql

insert into sm_oauth_security (CLIENT_AUTHCLASS, CLIENT_ID, CLIENT_NAME, CLIENT_SECURITY, CLIENT_URL, DR, PK_GROUP, PK_OAUTH_SECURITY, TS)
values (null, 'scjcoa', 'oa', 'qfidufeiuvsvieaguaisfjfgaeu', null, null, '0001A210000000000YQ8', 'scjcoa', '2022-10-03 14:08:34');

2.2.2 第三方系统设置

2.2.2.1 通过秘钥对获取登录token,第三方服务访 http://ip:port/service/genThirdPartyAccessToken

同时访问参数为:

  • type 获取方式,此方式为固定为 type_security且必需项;
  • dsname 数据源名称,必需项;
  • usercode NCC用户编码,必需项;
  • langcode 多语语种,非必需项,为空默认中文语种;
  • busicentercode 账套编码,非必需项,为空登录时会循环在数据源中查找用户;
  • ts ,第三方系统加签的时间,用来生成校验秘钥对,必需项;
  • client_id第三方系统id,即第一步在sm_oauth_security注册的系统编码,必需项;
  • security第三方由共同维护的秘钥对根据给定的算法自己生成的秘钥值,必需项。 security是通过SHA256加签,其中是根据usercode,ts,client_security和当前系统时间动态拼接的字符串生成。

2.2.2.2 提供登录NCC系统URL,token是从第二步成功返回结果,该值默认保留1分钟,超时或使用过一次则失效

URL信息如下:

2.3 获取TOKEN 用于单点登陆

2.3.1 直接通过注册获取 access_token

private String registerSSOToken(UserVO securityUser) throws BusinessException {
    InvocationInfoProxy.getInstance().setUserId(securityUser.getCuserid());
    String access_token = RandomUtils.genRandomNumber(0, "");
    NCCSSORegInfo ssoInfo = new NCCSSORegInfo();
    ssoInfo.setUsercode(securityUser.getUser_code());
    ssoInfo.setLangCode(Language);
    ssoInfo.setBusiCenterCode(BizCenterCode==null?"NCC":BizCenterCode);
    ssoInfo.setAccess_token(access_token);
    INCCSSOService lookup =NCLocator.getInstance().lookup(INCCSSOService.class);
    lookup.registerSSOInfo(ssoInfo);
    return access_token;
}

2.3.2 直接通过请求获取 access_token

public class Test { 
	public static void main(String[] args) throws Exception {
		// 在NC Cloud的系统注册表sm_oauth_security注册第三方系统
		String dsname = "nccloud_01";//数据源名称
		String usercode = "wst1";// ncc用户编码
		String client_id = "wst";// 第三方系统id
		String client_security = "qfidufeiuvsvieaguaisfjfgaeu";// 第三方秘钥
		String nccUrl = "http://127.0.0.1:8088/";

		URL preUrl = new URL(nccUrl + "service/genThirdPartyAccessToken");
		URLConnection uc = preUrl.openConnection();
		uc.setDoOutput(true);
		uc.setUseCaches(false);
		uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
		uc.setRequestProperty("Content-Length", "10000");
		uc.setRequestProperty("userid", usercode);
		HttpURLConnection hc = (HttpURLConnection) uc;
		hc.setRequestMethod("POST");
		OutputStream os = null;
		DataOutputStream dos = null;
		String returnFlag = "";
		InputStream is = null;
		try {
			StringBuffer sb = new StringBuffer();
			String ts = System.currentTimeMillis() + "";
			String security = genKey(usercode, usercode + client_security + ts.substring(0, 6));
			// 处理http请求参数+号变成空格问题
			security = security.replaceAll("\\+", "%2B");
			sb.append("type=type_security&ts=" + ts + "&dsname=" + dsname + "&usercode=" + usercode + "&client_id="
					+ client_id + "&security=" + security);
			os = hc.getOutputStream();
			dos = new DataOutputStream(os);
			dos.writeBytes(sb.toString());
			dos.flush();
			is = hc.getInputStream();
			int ch;
			while ((ch = is.read()) != -1) {
				returnFlag += String.valueOf((char) ch);
			}
			System.out.println("ncc-token"+returnFlag);
			String nccApiUrl = nccUrl;
			StringBuffer sso_url = new StringBuffer();
			
			//http://ip:port/uap/rbac/thirdpartylogin/main/index.html?accesstoken=xxx &redirect_uri=http://ip:port/nccloud
			sso_url.append(nccApiUrl + "nccloud/sso/thirdPartyLogin.sso?accesstoken=" + returnFlag);
			sso_url.append("&redirect_uri="+nccApiUrl+"nccloud");
			System.out.print("sso_url:"+sso_url.toString());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (dos != null) {
				try {
					dos.close();
				} catch (Exception e2) {
				}
			}
			if (os != null) {
				try {
					os.close();
				} catch (Exception e2) {
				}
			}
			if (is != null)
				try {
					is.close();
				} catch (Exception e2) {
				}
		}
	}

	private static String genKey(String userid, String key) throws Exception {
		return Base64Util.encryptBASE64((SignatureTookKit.digestSign(userid.getBytes(), key.getBytes())));
	}

2.4 HttpServlet接口为例

public class ThirdPartyAccessTokenServlet extends HttpServlet implements IHttpServletAdaptor {
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doAction(req, resp);
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doAction(req, resp);
	}

	public void doAction(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 初始化环境变量
		// 获取access_token
		// 执行跳转
	}
}

2.5 初始化环境变量

2.5.1 baseinfo.properties配置

#数据源
UserDataSource=design
#集团
GroupId=0001X1100000000003VE
#接口用户ID
UserId=1001X11000000000000W
#接口用户编码
UserCode=cyz
#业务中心代码--单点登陆使用开发环境develop生产环境是账套编码
BizCenterCode=NCC
# 开发环境3006 生产环境以设定的端口号为准
NccWebAddress=http://127.0.0.1:3006
# 固定跳转地址 (开发环境3006 生产环境以设定的端口号为准)
localweburl=http://127.0.0.1:3006/nccloud/resources/uap/rbac/thirdpartylogin/main/index.html?

2.5.2 读取环境变量并进行设置

private void environmentProxy(HttpServletRequest request) throws Exception {
        String UserDataSource = PropertiesUtils.getInstance().getStrValue("UserDataSource");
        String GroupId = PropertiesUtils.getInstance().getStrValue("GroupId");
        String BizCenterCode = PropertiesUtils.getInstance().getStrValue("BizCenterCode");
        InvocationInfoProxy.getInstance().setGroupId(GroupId);
        InvocationInfoProxy.getInstance().setUserDataSource(UserDataSource);
        InvocationInfoProxy.getInstance().setBizCenterCode(BizCenterCode);
}

2.6 执行跳转到NCC桌面

String nccWebAddress = PropertiesUtils.getInstance().getStrValue("nccWebAddress");
String toUrl = localweburl + "accesstoken=" + access_token + "&redirect_uri=" + nccWebAddress+ "/nccloud";
response.sendRedirect(toUrl);
//http://ip:port/uap/rbac/thirdpartylogin/main/index.html?accesstoken=xxx&redirect_uri=http://ip:port/nccloud