公司账号服务单点登录到gitlab
目标:使用oauth协议,点击挂在系统的gitlab链接,直接登录到gitlab的服务,如果没有账号则新建
操作:
一.服务端:
1.在自己的系统内添加oauth协议的包
<dependency>
<groupId>org.apache.oltu.oauth2</groupId>
<artifactId>org.apache.oltu.oauth2.authzserver</artifactId>
<version>0.31</version>
</dependency>
<dependency>
<groupId>org.apache.oltu.oauth2</groupId>
<artifactId>org.apache.oltu.oauth2.resourceserver</artifactId>
<version>0.31</version>
</dependency>
2.实现和client端交互的三个接口,接口之间的参数验证已经省略
(1).获取客户端 code,没遇到什么问题
import java.net.URI;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.apache.oltu.oauth2.common.message.types.ResponseType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class AuthorizeController {
private static Logger logger = LoggerFactory.getLogger(AuthorizeController.class);
@RequestMapping("/responseCode")
public Object toShowUser(Model model, HttpServletRequest request) {
logger.info("访问responseCode接口,获取状态码");
try {
OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);
//1.验证clientId
if ("********************".equals(oauthRequest.getClientId())) {
String authCode = null;
String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);
logger.info("responseType:" + responseType);
// ResponseType仅支持CODE和TOKEN
if (responseType.equals(ResponseType.CODE.toString())) {
OAuthIssuerImpl oAuthIssuer = new OAuthIssuerImpl(new MD5Generator());
authCode = oAuthIssuer.authorizationCode();
}
// 进行OAuth响应构建
OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse
.authorizationResponse(request, HttpServletResponse.SC_FOUND);
// 设置授权码,存储用来下一个请求认证
builder.setCode(authCode);
// 得到到客户端重定向地址
String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);
logger.info("redirectURI:" + redirectURI);
// 构建响应
final OAuthResponse response = builder.location(redirectURI).buildQueryMessage();
String responceUri = response.getLocationUri();
// 根据OAuthResponse返回ResponseEntity响应
HttpHeaders headers = new HttpHeaders();
try {
headers.setLocation(new URI(response.getLocationUri()));
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:" + responceUri;
}
} catch (Exception e) {
}
return null;
}
}
(2)生成access_token,在这块卡了很长时间,原因是返回值是Map的形式,gitlab官方也没有找到对返回值的规范,就写出来记录一下吧。
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.issuer.UUIDValueGenerator;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
@Controller
public class AccessTokenController {
private static Logger logger = LoggerFactory.getLogger(AccessTokenController.class);
// 获取客户端的code码,向客户端返回access token
@RequestMapping(value = "/responseAccessToken",method = RequestMethod.POST)
@ResponseBody
public Object token(HttpServletRequest request) {
logger.info("访问responseAccessToken接口 获取access_token");
OAuthIssuer oauthIssuerImpl = null;
OAuthResponse response = null;
// 构建OAuth请求
try {
OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request);
// 1.验证authcode
String authCode = oauthRequest.getParam(OAuth.OAUTH_CODE);
// 2.验证clientSecret
String clientSecret = oauthRequest.getClientSecret();
logger.info("clientSecret:" + clientSecret);
// 3.生成Access Token
oauthIssuerImpl = new OAuthIssuerImpl(new UUIDValueGenerator());
final String accessToken = oauthIssuerImpl.accessToken();
Map<String,String> resultMap = new HashMap<String,String>();
resultMap.put("access_token", accessToken);
resultMap.put("expires_in", "0");
return resultMap;
} catch (OAuthSystemException e) {
e.printStackTrace();
} catch (OAuthProblemException e) {
e.printStackTrace();
}
return null;
}
}
(3).通过access_token获取账号信息,这块的遇到的问题主要有两个,第一个是在request中没有取到access_token,试着打印了http完整的请求,发现在request之前会打印完整信息,但是request是取不到的,具体获取方法先如下。第二个问题是,用户同步的问题,id(感觉是为了保证唯一性,否则每次都是新建的账号),name,nickname,email,这四个参数是可以满足,新建gitlab账号,正常单点登录的问题。
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.oltu.oauth2.as.request.OAuthUnauthenticatedTokenRequest;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
@Controller
public class UserInfoController {
private static Logger logger = LoggerFactory.getLogger(UserInfoController.class);
@RequestMapping("/userInfo")
@ResponseBody
public Object userInfo(HttpServletRequest request) {
logger.info("访问userInfo接口 获取账号信息");
String header = request.getHeader("authorization");
String[] split = header.split(" ");
String accesstoken = split[1].trim();
// 1.验证token
//1.1验证token的过期时间
String username = commonUtils.getUsernameByToken(accesstoken);
if (StringUtils.isBlank(username)) {
return "";
}
// 2.取到账号信息返回
Map<String, Object> resultMap = new HashMap<String, Object>();
if ("zhangsan".equals(username)) {
resultMap.put("id", "111");
resultMap.put("name", "zhangsan");
resultMap.put("nickname", "zhangsan");
resultMap.put("email", "******@163.com");
} else if ("lisi".equals(username)) {
resultMap.put("id", "112");
resultMap.put("name", "lisi");
resultMap.put("nickname", "lisi");
resultMap.put("email", "lisi@163.com");
}
logger.info(JSON.toJSONString(resultMap));
ResponseEntity<Object> responseEntity = new ResponseEntity<Object>(resultMap, HttpStatus.valueOf(200));
return responseEntity;
}
}
二,是客户端gitlab的配置,主要修改 /etc/gitlab/gitlab.rb文件
配置的含义可以看gitlab官方解释,具体配置app_id和app_secret 自己和服务端关联起来就好,三个接口可以自己定义,gitlab有默认接口:
user_info_url: '/api/v3/user', # The endpoint on your OAuth 2 server that provides user info for the current user
authorize_url: '/oauth/authorize', # The authorization endpoint for your OAuth server
token_url: '/oauth/token' # The token request endpoint for your OAuth server
具体查看 oauth2_generic.rb 文件,忘了在哪个目录了
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_allow_single_sign_on'] = ['****']
gitlab_rails['omniauth_block_auto_created_users'] = false
#gitlab_rails['omniauth_auto_sign_in_with_provider'] = '****'
gitlab_rails['omniauth_providers'] = [
{
'name' => '****',
#'app_id' => '67bc4a4b7515a2cc5a31ab91d8bf953f68b21b08b701dc20c6102eec65d80e9c',
#'app_secret' => 'b9ca8154f8efc888ed95a44161ed1237fb0b8a84ea7fe2532eb879f812cf73d8',
'app_id' => '67bc4a4b7515a2cc5a31ab91d8bf953f68b21b08b701dc20c',
'app_secret' => 'b9ca8154f8efc888ed95a44161ed1237fb0b8a84ea7fe253',
'args' => {
client_options: {
'site' => 'http://127.0.0.1:8080',
'authorize_url' => '/v1/sso/responseCode',
'token_url' => '/v1/sso/responseAccessToken',
'user_info_url' => '/v1/sso/userInfo'
},
user_response_structure: {
root_path: [],
id_path: 'id',
attributes: {
name: 'name',
nickname: 'nickname',
email: 'email'
}
},
name: '****',
strategy_class: "OmniAuth::Strategies::OAuth2Generic"
}
}
]
至此,是可以满足正常的单点登录啦。
出现过的问题:
- 导航栏: 邮箱已经别注册,gitlab是一个邮箱对应一个账号
- 客户端会做token是否过期的判断,注意过期时间
- 对于gitlab已有的账号,需要关联一下账号 操作步骤:正常登录–>setting–>account–>Connected Accounts
还有剩余问题:
测试中出现
还有遇到的问题欢迎大家评论探讨。、
有帮助的话记得收藏点赞,谢谢。