✨ 添加新特性。 支持开源中国、码云登录

This commit is contained in:
冷冷 committed 2019-04-08 21:53:58 +08:00
1 parent f6094954b6
commit 5615b78c5e
13 files changed
+352 -9

No files matched your search

@@ -87,6 +87,7 @@ public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdap
.userDetailsService(pigxUserDetailsService)
.authenticationManager(authenticationManagerBean)
.reuseRefreshTokens(false)
.pathMapping("/oauth/confirm_access", "/token/confirm_access")
.exceptionTranslator(new PigxWebResponseExceptionTranslator());
}
@@ -39,11 +39,16 @@ import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -58,6 +63,7 @@ import java.util.Map;
@RequestMapping("/token")
public class PigxTokenEndpoint {
private static final String PIGX_OAUTH_ACCESS = SecurityConstants.PIGX_PREFIX + SecurityConstants.OAUTH_PREFIX + "auth_to_access:";
private final ClientDetailsService clientDetailsService;
private final RedisTemplate pigxRedisTemplate;
private final TokenStore tokenStore;
private final CacheManager cacheManager;
@@ -65,11 +71,37 @@ public class PigxTokenEndpoint {
/**
* 认证页面
*
* @param modelAndView
* @return ModelAndView
*/
@GetMapping("/login")
public ModelAndView require() {
return new ModelAndView("ftl/login");
public ModelAndView require(ModelAndView modelAndView) {
modelAndView.setViewName("ftl/login");
return modelAndView;
}
/**
* 确认授权页面
*
* @param request
* @param session
* @param modelAndView
* @return
*/
@GetMapping("/confirm_access")
public ModelAndView confirm(HttpServletRequest request, HttpSession session, ModelAndView modelAndView) {
Map<String, Object> scopeList = (Map<String, Object>) request.getAttribute("scopes");
modelAndView.addObject("scopeList", scopeList.keySet());
Object auth = session.getAttribute("authorizationRequest");
if (auth != null) {
AuthorizationRequest authorizationRequest = (AuthorizationRequest) auth;
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
modelAndView.addObject("app", clientDetails.getAdditionalInformation());
}
modelAndView.setViewName("ftl/confirm");
return modelAndView;
}
/**
@@ -15,7 +15,7 @@
* Author: lengleng (wangiegie@gmail.com)
*/
body {
.sign_body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
<title>PigX第三方授权</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="/css/signin.css"/>
</head>
<body>
<nav class="navbar navbar-default container-fluid">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">开放平台</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-5">
<p class="navbar-text navbar-right">
<a target="_blank" href="https://pig4cloud.com">技术支持</a>
</p>
</div>
</div>
</nav>
<div style="padding-top: 80px;width: 300px; color: #555; margin:0px auto;">
<form id='confirmationForm' name='confirmationForm' action="/oauth/authorize" method='post'>
<input name='user_oauth_approval' value='true' type='hidden'/>
<p><a href="${app.website}" target="_blank">${app.appName}</a> 将获得以下权限:</p>
<ul class="list-group">
<li class="list-group-item"> <span>
<#list scopeList as scope>
<input type="hidden" name="${scope}" value="true"/>
<input type="checkbox" disabled checked="checked"/><label>${scope}</label>
</#list>
</ul>
<p class="help-block">授权后表明你已同意 <a>服务协议</a></p>
<button class="btn btn-success pull-right" type="submit" id="write-email-btn">授权</button>
</p>
</form>
</div>
<footer>
<p>support by: pig4cloud.com</p>
<p>email: <a href="mailto:wangiegie@gmail.com">wangiegie@gmail.com</a>.</p>
</footer>
</body>
</html>
@@ -14,7 +14,7 @@
<link href="/css/signin.css" rel="stylesheet">
</head>
<body>
<body class="sign_body">
<div class="container form-margin-top">
<form class="form-signin" action="/token/form" method="post">
<h2 class="form-signin-heading" align="center">统一认证系统</h2>
@@ -24,7 +24,7 @@
</form>
</div>
<footer>
<p>support by: lengleng</p>
<p>support by: pig4cloud</p>
<p>email: <a href="mailto:wangiegie@gmail.com">wangiegie@gmail.com</a>.</p>
</footer>
</body>
@@ -93,6 +93,28 @@ public interface SecurityConstants {
String WX_AUTHORIZATION_CODE_URL = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
/**
* 码云获取token
*/
String GITEE_AUTHORIZATION_CODE_URL = "https://gitee.com/oauth/token?grant_type=" +
"authorization_code&code=%S&client_id=%s&redirect_uri=" +
"%s&client_secret=%s";
/**
* 开源中国获取token
*/
String OSC_AUTHORIZATION_CODE_URL = "https://www.oschina.net/action/openapi/token";
/**
* 码云获取用户信息
*/
String GITEE_USER_INFO_URL = "https://gitee.com/api/v5/user?access_token=%s";
/**
* 开源中国用户信息
*/
String OSC_USER_INFO_URL = "https://www.oschina.net/action/openapi/user?access_token=%s&dataType=json";
/**
* {bcrypt} 加密的特征码
*/
@@ -46,7 +46,17 @@ public enum LoginTypeEnum {
/**
* 微信登录
*/
WECHAT("WX", "微信登录");
WECHAT("WX", "微信登录"),
/**
* 码云登录
*/
GITEE("GITEE", "码云登录"),
/**
* 开源中国登录
*/
OSC("OSC", "开源中国登录");
/**
* 类型
@@ -105,4 +105,13 @@ public class SysUser implements Serializable {
*/
private String qqOpenid;
/**
* 码云唯一标识
*/
private String giteeLogin;
/**
* 开源中国唯一标识
*/
private String oscId;
}
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.admin.handler;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.admin.api.dto.UserInfo;
import com.pig4cloud.pigx.admin.api.entity.SysSocialDetails;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.admin.mapper.SysSocialDetailsMapper;
import com.pig4cloud.pigx.admin.service.SysUserService;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.constant.enums.LoginTypeEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
/**
* @author lengleng
* @date 2019/4/8
* <p>
* 码云登录
*/
@Slf4j
@Component("GITEE")
@AllArgsConstructor
public class GiteeLoginHandler extends AbstractLoginHandler {
private final SysSocialDetailsMapper sysSocialDetailsMapper;
private final SysUserService sysUserService;
/**
* 码云登录传入code
* <p>
* 通过code 调用qq 获取唯一标识
*
* @param code
* @return
*/
@Override
public String identify(String code) {
SysSocialDetails condition = new SysSocialDetails();
condition.setType(LoginTypeEnum.GITEE.getType());
SysSocialDetails socialDetails = sysSocialDetailsMapper.selectOne(new QueryWrapper<>(condition));
String url = String.format(SecurityConstants.GITEE_AUTHORIZATION_CODE_URL, code
, socialDetails.getAppId(), URLUtil.encode(socialDetails.getRedirectUrl()), socialDetails.getAppSecret());
String result = HttpUtil.post(url, new HashMap<>(0));
log.debug("码云响应报文:{}", result);
String accessToken = JSONUtil.parseObj(result).getStr("access_token");
String userUrl = String.format(SecurityConstants.GITEE_USER_INFO_URL, accessToken);
String resp = HttpUtil.get(userUrl);
log.debug("码云获取个人信息返回报文{}", resp);
JSONObject userInfo = JSONUtil.parseObj(resp);
//码云唯一标识
String login = userInfo.getStr("login");
return login;
}
/**
* identify 获取用户信息
*
* @param identify identify
* @return
*/
@Override
public UserInfo info(String identify) {
SysUser user = sysUserService
.getOne(Wrappers.<SysUser>query()
.lambda().eq(SysUser::getGiteeLogin, identify));
if (user == null) {
log.info("码云未绑定:{}", identify);
return null;
}
return sysUserService.findUserInfo(user);
}
}
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.admin.handler;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.admin.api.dto.UserInfo;
import com.pig4cloud.pigx.admin.api.entity.SysSocialDetails;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.admin.mapper.SysSocialDetailsMapper;
import com.pig4cloud.pigx.admin.service.SysUserService;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.constant.enums.LoginTypeEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author lengleng
* @date 2019/4/8
* <p>
* 开源中国登录
*/
@Slf4j
@Component("OSC")
@AllArgsConstructor
public class OscChinaLoginHandler extends AbstractLoginHandler {
private final SysSocialDetailsMapper sysSocialDetailsMapper;
private final SysUserService sysUserService;
/**
* 开源中国传入code
* <p>
* 通过code 调用qq 获取唯一标识
*
* @param code
* @return
*/
@Override
public String identify(String code) {
SysSocialDetails condition = new SysSocialDetails();
condition.setType(LoginTypeEnum.OSC.getType());
SysSocialDetails socialDetails = sysSocialDetailsMapper.selectOne(new QueryWrapper<>(condition));
Map<String, Object> params = new HashMap<>(8);
params.put("client_id", socialDetails.getAppId());
params.put("client_secret", socialDetails.getAppSecret());
params.put("grant_type", "authorization_code");
params.put("redirect_uri", socialDetails.getRedirectUrl());
params.put("code", code);
params.put("dataType", "json");
String result = HttpUtil.post(SecurityConstants.OSC_AUTHORIZATION_CODE_URL, params);
log.debug("开源中国响应报文:{}", result);
String accessToken = JSONUtil.parseObj(result).getStr("access_token");
String url = String.format(SecurityConstants.OSC_USER_INFO_URL, accessToken);
String resp = HttpUtil.get(url);
log.debug("开源中国获取个人信息返回报文{}", resp);
JSONObject userInfo = JSONUtil.parseObj(resp);
//开源中国唯一标识
String id = userInfo.getStr("id");
return id;
}
/**
* identify 获取用户信息
*
* @param identify 开源中国表示
* @return
*/
@Override
public UserInfo info(String identify) {
SysUser user = sysUserService
.getOne(Wrappers.<SysUser>query()
.lambda().eq(SysUser::getOscId, identify));
if (user == null) {
log.info("开源中国未绑定:{}", identify);
return null;
}
return sysUserService.findUserInfo(user);
}
}
@@ -41,7 +41,6 @@ import org.springframework.web.client.RestTemplate;
@Component("WX")
@AllArgsConstructor
public class WeChatLoginHandler extends AbstractLoginHandler {
private final RestTemplate restTemplate;
private final SysUserService sysUserService;
private final SysSocialDetailsMapper sysSocialDetailsMapper;
@@ -25,6 +25,7 @@ import com.pig4cloud.pigx.admin.handler.LoginHandler;
import com.pig4cloud.pigx.admin.mapper.SysSocialDetailsMapper;
import com.pig4cloud.pigx.admin.mapper.SysUserMapper;
import com.pig4cloud.pigx.admin.service.SysSocialDetailsService;
import com.pig4cloud.pigx.common.core.constant.enums.LoginTypeEnum;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -56,7 +57,15 @@ public class SysSocialDetailsServiceImpl extends ServiceImpl<SysSocialDetailsMap
public Boolean bindSocial(String type, String code) {
String identify = loginHandlerMap.get(type).identify(code);
SysUser sysUser = sysUserMapper.selectById(SecurityUtils.getUser().getId());
sysUser.setWxOpenid(identify);
if (LoginTypeEnum.GITEE.getType().equals(type)) {
sysUser.setGiteeLogin(identify);
} else if (LoginTypeEnum.OSC.getType().equals(type)) {
sysUser.setOscId(identify);
} else if (LoginTypeEnum.WECHAT.getType().equals(type)) {
sysUser.setWxOpenid(identify);
} else if (LoginTypeEnum.QQ.getType().equals(type)) {
sysUser.setQqOpenid(identify);
}
sysUserMapper.updateById(sysUser);
//更新緩存
cacheManager.getCache("user_details").evict(sysUser.getUsername());
+1 -1
View File
@@ -194,7 +194,7 @@
</dependencyManagement>
<build>
<finalName>${project.name}</finalName>
<finalName>${project.artifactId}</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>