废话少说,直接上代码。。。
/**
* 对外提供第三方接口
* @author reyco
* @date 2019年8月9日
*
*/
public interface DevelopService {
/**
* 重定向授权登录页
* @param client_id id
* @param response_type 默认code
* @param redirect_uri 回调地址
* @return
*/
Result authorize(String client_id,String response_type,String redirect_uri);
/**
* 验证登录,生成token信息
* @param username 用户名
* @param password 密码
* @return
*/
Result setToken(String username,String password);
/**
* 生成token信息
* @param client_id id
* @param client_secret key
* @param redirect_uri 回调地址
* @param code 登录成功返回的code
* @param grant_type 默认authorization_code
* @return
* @throws Exception
*/
Result access_token(String client_id,String client_secret,String redirect_uri,String code,String grant_type) throws Exception;
/**
* 生成用户信息
* @param access_token token
* @return
*/
Result get_user_info(String access_token);
}
/**
* 对外第三方接口实现类
* @author reyco
* @date 2019年8月14日
*
*/
@Service("developService")
public class DevelopServiceImpl implements DevelopService {
/**
* 第三方绑定运用绑定
*/
@Autowired
private ApplicationService applicationService;
/**
* 用户信息
*/
@Autowired
private AccountsService accountsService;
/**
* redis
*/
@Autowired
private RedisTemplate redisTemplate;
@Override
public Result authorize(String client_id, String response_type, String redirect_uri) {
Result result = new Result();
// 1. 非空判断
if (StringUtils.isBlank(client_id) || StringUtils.isBlank(redirect_uri) || StringUtils.isBlank(response_type)) {
result.setMsg("参数错误");
return result;
}
// 2. 验证参数
Application application = applicationService.searchApplication(client_id);
// 2.1 验证失败
if (null == application) {
result.setMsg("应用不存在");
return result;
}
if (!application.getRedirect_uri().equals(redirect_uri)) {
result.setMsg("回调地址错误");
return result;
}
if (!response_type.equals("code")) {
result.setMsg("response_type错误");
return result;
}
// 2.2 验证成功
result.setIsTrue(true);
return result;
}
@Override
public Result setToken(String username, String password) {
// 1. 验证登录
Result result = accountsService.isLogin(username, password);
if (!result.isTrue()) {
return result;
}
// 2. 获取用户信息
Accounts accounts = (Accounts) result.getData();
// 3. 生成token
String code = UUID.randomUUID().toString().replace("-", "");
// 3.1 生成token
String token = JWTUtils.createJWT(code, "token", JWTUtils.generalSubject(accounts), 1000 * 10 * 60);
// 3.2 token放入redis,有效时间10分钟
ValueOperations opsForValue = redisTemplate.opsForValue();
opsForValue.set(code, token, 10 * 60, TimeUnit.SECONDS);
// 4. 响应
result.setData(code);
return result;
}
@Override
public Result access_token(String client_id, String client_secret, String redirect_uri, String code,
String grant_type) throws Exception {
Result result = new Result();
// 1. 非空判断
if (StringUtils.isBlank(code) || StringUtils.isBlank(client_id) || StringUtils.isBlank(redirect_uri)
|| StringUtils.isBlank(client_secret) || StringUtils.isBlank(grant_type)) {
result.setMsg(JSONResult.ERROR_PARAMS);
return result;
}
// 2. 获取applicationResult对象
Result applicationResult = applicationService.getApplication(client_id);
// 3. 获取applicationResult对象是否成功
if (!applicationResult.isTrue()) {
result.setMsg(JSONResult.ERROR_PARAMS);
return result;
}
// 4. 获取applicationResult对象成功后,获取application对象
Application application = (Application) applicationResult.getData();
// 参数是否有误
if (!application.getRedirect_uri().equals(redirect_uri) || !application.getClient_secret().equals(client_secret)
|| !"authorization_code".equals(grant_type)) {
result.setMsg(JSONResult.ERROR_PARAMS);
return result;
}
// 5. 验证token
// 5.1 token是否存在
if (!redisTemplate.hasKey(code)) {
result.setMsg(JSONResult.ERROR_PARAMS);
return result;
}
ValueOperations opsForValue = redisTemplate.opsForValue();
// 5.2 根据code获取token
String token = opsForValue.get(code);
// 5.3 验证token信息
JWTResult validateJWT = JWTUtils.validateJWT(token);
// 获取claims信息
Claims claims = validateJWT.getClaims();
// 5.4 token是否失效
// 失效时间
Date expirationDate = claims.getExpiration();
// 当前时间
Date nowDate = new Date();
if (nowDate.after(expirationDate)) {
result.setMsg("token已失效");
return result;
}
// 6. 生成token信息
String subject = claims.getSubject();
// 6.1 获取用户信息
Accounts accounts = JsonUtils.jsonToPojo(subject, Accounts.class);
String uid = accounts.getUid();
// 6.2 token存储对象
JSONObject tokenObj = new JSONObject();
long expirationTime = expirationDate.getTime();
long nowtime = nowDate.getTime();
// token有效时间
long expires_in = (expirationTime - nowtime);
tokenObj.put("access_token", token);
tokenObj.put("expires_in", "" + expires_in);
tokenObj.put("remind_in", "1234");
tokenObj.put("uid", uid);
result.setData(tokenObj);
result.setIsTrue(true);
return result;
}
@Override
public Result get_user_info(String access_token) {
Result result = new Result();
try {
// 1. 非空判断
if (StringUtils.isBlank(access_token)) {
result.setMsg(JSONResult.ERROR_PARAMS);
return result;
}
// 2. 验证token信息
JWTResult validateJWT = JWTUtils.validateJWT(access_token);
// 2.1 获取claims信息
Claims claims = validateJWT.getClaims();
// 2.2 token失效时间
Date expirationDate = claims.getExpiration();
// 当前时间
Date nowDate = new Date();
if (nowDate.after(expirationDate)) {
result.setMsg("token已失效");
return result;
}
// 获取token主题信息
String subject = claims.getSubject();
// 3. 获取用户信息
Accounts accounts = JsonUtils.jsonToPojo(subject, Accounts.class);
// 3.1 user存储对象
JSONObject userInfoObj = new JSONObject();
userInfoObj.put("nickname", accounts.getNickname());
userInfoObj.put("scope", "");
userInfoObj.put("create_at", accounts.getGmtCreate());
userInfoObj.put("uid", accounts.getUid());
result.setData(userInfoObj);
result.setIsTrue(true);
return result;
} catch (JSONException e) {
e.printStackTrace();
}
result.setMsg("token无效");
return result;
}
}
/**y
* 模拟第三方登录开发接口
* @author reyco
* @date 2019年7月26日
*
*/
@RequestMapping("oauth2")
@Controller
public class DevelopController {
@Autowired
private DevelopService developService;
/**
* 重定向授权登录页
* @param client_id id
* @param response_type 响应类型默认code
* @param redirect_uri 第三方回调地址
* @param request
* @return
* @throws IOException
*/
@RequestMapping("authorize")
public String authorize(String client_id,String response_type,String redirect_uri) throws IOException {
// 验证参数
Result result = developService.authorize(client_id, response_type, redirect_uri);
// 验证参数有误
if(!result.isTrue()) {
return "../error.html";
}
// 验证参数无误,重定向登录页面
return "../login.html";
}
/**
* 验证登录,生成token
* @param username 用户名
* @param password 密码
* @param redirect_uri 第三方回调地址(建议前端放在请求头中)
* @return
*/
@ResponseBody
@RequestMapping("login")
public String login(String username,String password,String redirect_uri) {
// 验证登录,设置token
Result result = developService.setToken(username, password);
// 验证登录失败
if(!result.isTrue()) {
return JSONResult.failCreate("用户名或密码错误", result.getMsg()).toJSON();
}
// 验证登录失败
String code = (String)result.getData();
if(!redirect_uri.contains("?")) {
redirect_uri = redirect_uri+"?code="+code;
}else {
redirect_uri = redirect_uri+"&code="+code;
}
return JSONResult.create(redirect_uri).toJSON();
}
/**
* 获取token信息
* @param code 登录验证成功返回的code
* @param client_id id
* @param client_secret key
* @param grant_type 默认authorization_code
* @param redirect_uri 第三方回调地址
* @param request
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping("access_token")
public String access_token(String code,String client_id,String client_secret,String grant_type,String redirect_uri,HttpServletRequest request) throws Exception {
// 生成token信息
Result accessTokenResult = developService.access_token(client_id,client_secret,redirect_uri, code, grant_type);
// 失败
if(!accessTokenResult.isTrue()) {
return accessTokenResult.getMsg();
}
// 成功,响应token
Object token = accessTokenResult.getData();
return token.toString();
}
/**
* 获取用户信息
* @param access_token token
* @param request
* @return
* @throws JSONException
*/
@ResponseBody
@RequestMapping("get_user_info")
public String get_user_info(String access_token,HttpServletRequest request) throws JSONException {
// 生成用户信息
Result get_user_info_result = developService.get_user_info(access_token);
// 失败
if(!get_user_info_result.isTrue()) {
return get_user_info_result.getMsg();
}
// 成功,响应用户信息
Object token = get_user_info_result.getData();
return token.toString();
}
}
#dyw
dyw.id=a5f452dddd19d8ba
dyw.key=6e72a3e8974b44ad8a4de3c14a6abbbc
dyw.authorize_url=http://login.test.com/oauth2/authorize.do
dyw.callback=http://login.test.com/login/callback.do?type=dyw
dyw.get_token_url=http://login.test.com/oauth2/access_token.do
dyw.get_token_info=http://login.test.com/oauth2/get_user_info.do
/**
* 第三方登录顶级接口
*
* @author reyco
* @date 2019年7月23日
*
*/
public interface LoginService {
/**
* 登录 ---返回重定向地址
* @return
*/
String login()throws Exception;
/**
* 回调地址
* @param code 登录成功后返回的code
* @param request 参数request
* @return
* @throws Exception
*/
String callback(String code,HttpServletRequest request,HttpServletResponse response) throws Exception;
}
@Service("dyw")
public class DYWLoginServiceImpl implements LoginService{
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private AccountService accountService;
@Autowired
private RestTemplate restTemplate;
@Autowired
private RedisTemplate redisTemplate;
@Override
public String login() throws Exception {
// 回调地址
String backUrl = PropertiesUtil.getValue("dyw.callback");
String authorize_url = PropertiesUtil.getValue("dyw.authorize_url");
// appid
String dywID = PropertiesUtil.getValue("dyw.id");
String state = UUID.randomUUID().toString().replaceAll("-", "");
String url=authorize_url
+ "?client_id="+dywID
+ "&response_type=code"
+ "&redirect_uri="+URLEncoder.encode(backUrl)
+ "&state="+state;
return url;
}
@Override
public String callback(String code, HttpServletRequest request, HttpServletResponse response) throws Exception {
JSONObject accessToken = getAccessToken(code);
String token = accessToken.getString("access_token");
JSONObject userInfo = getUserInfo(token);
String uid = userInfo.getString("uid");
String nickname = userInfo.getString("nickname");
boolean flag = accountService.searchCountByPhone(uid);
if(flag) {
// 用户信息
Integer type=Type.DYW;
Integer integral = 0;
String phone=uid;
String name = nickname;
String password = "e10adc3949ba59abbe56e057f20f883e";
Integer status = Status.NORMAL;
Integer gender = 1;
String desc = "点击修改备注";
//注册用户
accountService.register(type, integral, phone, password, name, gender, null, null, status, desc);
}
Account account = accountService.getAccount(uid);
// 获取登录用户
String loginPhone = account.getPhone();
// 是否其它客户端已登录---如果已登录则强制退出
ValueOperations opsForValue = redisTemplate.opsForValue();
if(redisTemplate.hasKey(loginPhone)) {
// 判断redis中是否存在该用户key,并获取
Object phoneValue = opsForValue.get(loginPhone);
redisTemplate.delete(loginPhone);
// 判断redis中是否存在cookie
if(redisTemplate.hasKey(phoneValue.toString())) {
redisTemplate.delete(phoneValue.toString());
}
}
Integer id = account.getId();
Integer vipId = account.getVipId();
// 获取登录ip
String ip = CusAccessObjectUtil.getIpAddress(request);
// 获取登录城市
String cityName = IPDataUtils.getCityName(ip);
String loginName = account.getName();
User u = new User(id,loginPhone,vipId,ip, cityName, loginName);
// 生成cookie的key
String key = UUID.randomUUID().toString().replace("-", "");
// 保存到redis
opsForValue.set(key, JsonUtils.objectToJson(u),30*60,TimeUnit.SECONDS);
opsForValue.set(loginPhone, key,30*60,TimeUnit.SECONDS);
// 生成cookie
CookieUtil.setCookie(request, response, "user_token", key, -1);
return "http://login.test.com/user/index.html";
}
/**
* 获取token信息
* @param code
* @return
* @throws Exception
*/
private JSONObject getAccessToken(String code) throws Exception {
String dywID = PropertiesUtil.getValue("dyw.id");
String dywKey = PropertiesUtil.getValue("dyw.key");
String callback = PropertiesUtil.getValue("dyw.callback");
String get_token_url = PropertiesUtil.getValue("dyw.get_token_url");
get_token_url=get_token_url+"?grant_type=authorization_code" + "&client_id="
+ dywID + "&client_secret=" + dywKey + "&redirect_uri=" + callback + "&code=" + code;
String tokenObject = restTemplate.getForObject(get_token_url,String.class);
JSONObject dywTokenObject = new JSONObject(tokenObject);
logger.info("dyw."+dywTokenObject.toString());
return dywTokenObject;
}
/**
* 获取用户信息
* @param token
* @return
* @throws Exception
*/
private JSONObject getUserInfo(String token) throws Exception {
String get_userInfo_url = PropertiesUtil.getValue("dyw.get_token_info");
String get_user_info_url=get_userInfo_url+"?access_token="+token;
String userInfoObject = restTemplate.getForObject(get_user_info_url,String.class);
JSONObject dywUserInfoObject = new JSONObject(userInfoObject);
logger.info("dyw."+dywUserInfoObject.toString());
return dywUserInfoObject;
}
}
@Component("loginServiceContext")
public class LoginServiceContext {
@Autowired
private Map loginSerivceMap = new HashMap();
/**
* 重定向地址
* @param type
* @return
* @throws Exception
*/
public String login(String type) throws Exception {
return loginSerivceMap.get(type).login();
}
/**
* 回调地址
* @param type
* @param request
* @param response
* @return
* @throws Exception
*/
public String callback(String code,String type,HttpServletRequest request,HttpServletResponse response) throws Exception {
return loginSerivceMap.get(type).callback(code,request,response);
}
}
@RequestMapping("login")
@Controller
public class LoginController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private LoginServiceContext loginServiceContext;
@RequestMapping("login")
public String login(String type) throws Exception {
String redirectUrl = loginServiceContext.login(type);
logger.info(redirectUrl);
return "redirect:"+redirectUrl;
}
@RequestMapping("callback")
public String callback(HttpServletRequest request,HttpServletResponse response,String code,String type) throws Exception {
String callback = loginServiceContext.callback(code,type, request,response);
return "redirect:"+callback;
}
}
对外提供第三方登录接口本地测试,其中一个账号:reyco,密码:123456。