OAuth2.0模块 beta

This commit is contained in:
click33
2021-07-17 23:14:23 +08:00
parent 93e231ff18
commit 742b65366a
29 changed files with 1655 additions and 712 deletions

View File

@@ -1,5 +1,6 @@
package cn.dev33.satoken.context.model; package cn.dev33.satoken.context.model;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaFoxUtil; import cn.dev33.satoken.util.SaFoxUtil;
/** /**
@@ -20,7 +21,7 @@ public interface SaRequest {
* @param name 键 * @param name 键
* @return 值 * @return 值
*/ */
public String getParameter(String name); public String getParam(String name);
/** /**
* 在 [请求体] 里获取一个值,值为空时返回默认值 * 在 [请求体] 里获取一个值,值为空时返回默认值
@@ -28,14 +29,39 @@ public interface SaRequest {
* @param defaultValue 值为空时的默认值 * @param defaultValue 值为空时的默认值
* @return 值 * @return 值
*/ */
public default String getParameter(String name, String defaultValue) { public default String getParam(String name, String defaultValue) {
String value = getParameter(name); String value = getParam(name);
if(SaFoxUtil.isEmpty(value)) { if(SaFoxUtil.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
return value; return value;
} }
/**
* 检测提供的参数是否为指定值
* @param name 键
* @param value 值
* @return 是否相等
*/
public default boolean isParam(String name, String value) {
String paramValue = getParam(name);
return paramValue != null && paramValue.equals(value);
}
/**
* 在 [请求体] 里获取一个值 (此值必须存在,否则抛出异常
* @param name 键
* @return 参数值
*/
public default String getParamNotNull(String name) {
String paramValue = getParam(name);
if(SaFoxUtil.isEmpty(paramValue)) {
throw new SaTokenException("缺少参数:" + name);
}
return paramValue;
}
/** /**
* 在 [请求头] 里获取一个值 * 在 [请求头] 里获取一个值
* @param name 键 * @param name 键

View File

@@ -30,7 +30,7 @@ public interface SaTokenDao {
* 写入Value并设定存活时间 (单位: 秒) * 写入Value并设定存活时间 (单位: 秒)
* @param key 键名称 * @param key 键名称
* @param value 值 * @param value 值
* @param timeout 过期时间 * @param timeout 过期时间(值>0时限时存储值=-1时永久存储值=0或<=-2时不存储)
*/ */
public void set(String key, String value, long timeout); public void set(String key, String value, long timeout);
@@ -75,7 +75,7 @@ public interface SaTokenDao {
* 写入Object并设定存活时间 (单位: 秒) * 写入Object并设定存活时间 (单位: 秒)
* @param key 键名称 * @param key 键名称
* @param object 值 * @param object 值
* @param timeout 存活时间 * @param timeout 存活时间 (值>0时限时存储值=-1时永久存储值=0或<=-2时不存储)
*/ */
public void setObject(String key, Object object, long timeout); public void setObject(String key, Object object, long timeout);

View File

@@ -45,6 +45,9 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
@Override @Override
public void set(String key, String value, long timeout) { public void set(String key, String value, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
dataMap.put(key, value); dataMap.put(key, value);
expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000));
} }
@@ -84,6 +87,9 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
@Override @Override
public void setObject(String key, Object object, long timeout) { public void setObject(String key, Object object, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
dataMap.put(key, object); dataMap.put(key, object);
expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000));
} }

View File

@@ -39,19 +39,19 @@ public class SaSsoHandle {
return sso.notLoginView.get(); return sso.notLoginView.get();
} }
// 情况2在SSO认证中心已经登录开始构建授权重定向地址下放ticket // 情况2在SSO认证中心已经登录开始构建授权重定向地址下放ticket
String redirectUrl = SaSsoUtil.buildRedirectUrl(stpLogic.getLoginId(), req.getParameter(ParamName.redirect)); String redirectUrl = SaSsoUtil.buildRedirectUrl(stpLogic.getLoginId(), req.getParam(ParamName.redirect));
return res.redirect(redirectUrl); return res.redirect(redirectUrl);
} }
// ---------- SSO-Server端RestAPI 登录接口 // ---------- SSO-Server端RestAPI 登录接口
if(match(Api.ssoDoLogin)) { if(match(Api.ssoDoLogin)) {
return sso.doLoginHandle.apply(req.getParameter("name"), req.getParameter("pwd")); return sso.doLoginHandle.apply(req.getParam("name"), req.getParam("pwd"));
} }
// ---------- SSO-Server端校验ticket 获取账号id // ---------- SSO-Server端校验ticket 获取账号id
if(match(Api.ssoCheckTicket) && sso.isHttp) { if(match(Api.ssoCheckTicket) && sso.isHttp) {
String ticket = req.getParameter(ParamName.ticket); String ticket = req.getParam(ParamName.ticket);
String sloCallback = req.getParameter(ParamName.ssoLogoutCall); String sloCallback = req.getParam(ParamName.ssoLogoutCall);
// 校验ticket获取对应的账号id // 校验ticket获取对应的账号id
Object loginId = SaSsoUtil.checkTicket(ticket); Object loginId = SaSsoUtil.checkTicket(ticket);
@@ -65,8 +65,8 @@ public class SaSsoHandle {
// ---------- SSO-Server端单点注销 // ---------- SSO-Server端单点注销
if(match(Api.ssoLogout) && sso.isSlo) { if(match(Api.ssoLogout) && sso.isSlo) {
String loginId = req.getParameter(ParamName.loginId); String loginId = req.getParam(ParamName.loginId);
String secretkey = req.getParameter(ParamName.secretkey); String secretkey = req.getParam(ParamName.secretkey);
// 遍历通知Client端注销会话 // 遍历通知Client端注销会话
SaSsoUtil.singleLogout(secretkey, loginId, url -> sso.sendHttp.apply(url)); SaSsoUtil.singleLogout(secretkey, loginId, url -> sso.sendHttp.apply(url));
@@ -93,8 +93,8 @@ public class SaSsoHandle {
// ---------- SSO-Client端登录地址 // ---------- SSO-Client端登录地址
if(match(Api.ssoLogin)) { if(match(Api.ssoLogin)) {
String back = req.getParameter(ParamName.back, "/"); String back = req.getParam(ParamName.back, "/");
String ticket = req.getParameter(ParamName.ticket); String ticket = req.getParam(ParamName.ticket);
// 如果当前Client端已经登录则无需访问SSO认证中心可以直接返回 // 如果当前Client端已经登录则无需访问SSO认证中心可以直接返回
if(stpLogic.isLogin()) { if(stpLogic.isLogin()) {
@@ -138,10 +138,10 @@ public class SaSsoHandle {
// ---------- SSO-Client端单点注销 [模式二] // ---------- SSO-Client端单点注销 [模式二]
if(match(Api.ssoLogout) && sso.isSlo && sso.isHttp == false) { if(match(Api.ssoLogout) && sso.isSlo && sso.isHttp == false) {
stpLogic.logout(); stpLogic.logout();
if(req.getParameter(ParamName.back) == null) { if(req.getParam(ParamName.back) == null) {
return SaResult.ok("单点注销成功"); return SaResult.ok("单点注销成功");
} else { } else {
return res.redirect(req.getParameter(ParamName.back, "/")); return res.redirect(req.getParam(ParamName.back, "/"));
} }
} }
@@ -155,10 +155,10 @@ public class SaSsoHandle {
String url = SaSsoUtil.buildSloUrl(stpLogic.getLoginId()); String url = SaSsoUtil.buildSloUrl(stpLogic.getLoginId());
String body = String.valueOf(sso.sendHttp.apply(url)); String body = String.valueOf(sso.sendHttp.apply(url));
if(SaSsoConsts.OK.equals(body)) { if(SaSsoConsts.OK.equals(body)) {
if(req.getParameter(ParamName.back) == null) { if(req.getParam(ParamName.back) == null) {
return SaResult.ok("单点注销成功"); return SaResult.ok("单点注销成功");
} else { } else {
return res.redirect(req.getParameter(ParamName.back, "/")); return res.redirect(req.getParam(ParamName.back, "/"));
} }
} }
return SaResult.error("单点注销失败"); return SaResult.error("单点注销失败");
@@ -166,8 +166,8 @@ public class SaSsoHandle {
// ---------- SSO-Client端单点注销的回调 [模式三] // ---------- SSO-Client端单点注销的回调 [模式三]
if(match(Api.ssoLogoutCall) && sso.isSlo && sso.isHttp) { if(match(Api.ssoLogoutCall) && sso.isSlo && sso.isHttp) {
String loginId = req.getParameter(ParamName.loginId); String loginId = req.getParam(ParamName.loginId);
String secretkey = req.getParameter(ParamName.secretkey); String secretkey = req.getParam(ParamName.secretkey);
SaSsoUtil.checkSecretkey(secretkey); SaSsoUtil.checkSecretkey(secretkey);
stpLogic.logoutByTokenValue(stpLogic.getTokenValueByLoginId(loginId)); stpLogic.logoutByTokenValue(stpLogic.getTokenValueByLoginId(loginId));

View File

@@ -132,7 +132,7 @@ public class StpLogic {
} }
// 2. 尝试从请求体里面读取 // 2. 尝试从请求体里面读取
if(tokenValue == null && config.getIsReadBody()){ if(tokenValue == null && config.getIsReadBody()){
tokenValue = request.getParameter(keyTokenName); tokenValue = request.getParam(keyTokenName);
} }
// 3. 尝试从header里读取 // 3. 尝试从header里读取
if(tokenValue == null && config.getIsReadHead()){ if(tokenValue == null && config.getIsReadHead()){

View File

@@ -204,7 +204,7 @@ public class SaFoxUtil {
if(url == null) { if(url == null) {
url = ""; url = "";
} }
int index = url.indexOf('?'); int index = url.lastIndexOf('?');
// ? 不存在 // ? 不存在
if(index == -1) { if(index == -1) {
return url + '?' + parameStr; return url + '?' + parameStr;
@@ -236,11 +236,63 @@ public class SaFoxUtil {
*/ */
public static String joinParam(String url, String key, Object value) { public static String joinParam(String url, String key, Object value) {
// 如果参数为空, 直接返回 // 如果参数为空, 直接返回
if(isEmpty(url) || isEmpty(key) || isEmpty(String.valueOf(value))) { if(isEmpty(url) || isEmpty(key) || isEmpty(value)) {
return url; return url;
} }
return joinParam(url, key + "=" + value); return joinParam(url, key + "=" + value);
} }
/**
* 在url上拼接锚参数
* @param url url
* @param parameStr 参数, 例如 id=1001
* @return 拼接后的url字符串
*/
public static String joinSharpParam(String url, String parameStr) {
// 如果参数为空, 直接返回
if(parameStr == null || parameStr.length() == 0) {
return url;
}
if(url == null) {
url = "";
}
int index = url.lastIndexOf('#');
// ? 不存在
if(index == -1) {
return url + '#' + parameStr;
}
// ? 是最后一位
if(index == url.length() - 1) {
return url + parameStr;
}
// ? 是其中一位
if(index > -1 && index < url.length() - 1) {
String separatorChar = "&";
// 如果最后一位是 不是&, 且 parameStr 第一位不是 &, 就增送一个 &
if(url.lastIndexOf(separatorChar) != url.length() - 1 && parameStr.indexOf(separatorChar) != 0) {
return url + separatorChar + parameStr;
} else {
return url + parameStr;
}
}
// 正常情况下, 代码不可能执行到此
return url;
}
/**
* 在url上拼接锚参数
* @param url url
* @param key 参数名称
* @param value 参数值
* @return 拼接后的url字符串
*/
public static String joinSharpParam(String url, String key, Object value) {
// 如果参数为空, 直接返回
if(isEmpty(url) || isEmpty(key) || isEmpty(value)) {
return url;
}
return joinSharpParam(url, key + "=" + value);
}
/** /**
* 将数组的所有元素使用逗号拼接在一起 * 将数组的所有元素使用逗号拼接在一起

View File

@@ -43,7 +43,7 @@
</dependency> </dependency>
<!-- sa-token整合redis (使用jackson序列化方式) --> <!-- sa-token整合redis (使用jackson序列化方式) -->
<!-- <dependency> <dependency>
<groupId>cn.dev33</groupId> <groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis-jackson</artifactId> <artifactId>sa-token-dao-redis-jackson</artifactId>
<version>${sa-token-version}</version> <version>${sa-token-version}</version>
@@ -51,7 +51,7 @@
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId> <artifactId>commons-pool2</artifactId>
</dependency> --> </dependency>
<!-- ConfigurationProperties --> <!-- ConfigurationProperties -->
<dependency> <dependency>

View File

@@ -12,7 +12,7 @@ public class SaOAuth2ServerApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(SaOAuth2ServerApplication.class, args); SpringApplication.run(SaOAuth2ServerApplication.class, args);
System.out.println("\n服务端启动成功"); System.out.println("\nOAuth-Server端启动成功");
} }
} }

View File

@@ -7,23 +7,187 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.pj.utils.AjaxJson; import com.pj.utils.AjaxJson;
import com.pj.utils.SoMap; import com.pj.utils.SoMap;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Handle;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Util; import cn.dev33.satoken.oauth2.logic.SaOAuth2Util;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Param;
import cn.dev33.satoken.oauth2.model.AccessTokenModel; import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel; import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel; import cn.dev33.satoken.oauth2.model.RequestAuthModel;
import cn.dev33.satoken.spring.SpringMVCUtil;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
@RestController @RestController
@RequestMapping("/oauth2/") //@RequestMapping("/oauth2/")
public class OAuth2Controller { public class OAuth2Controller {
// OAuth-Server端处理所有OAuth相关请求
@RequestMapping("/oauth2/authorize")
public Object request() {
System.out.println("------------进入请求:" + SaHolder.getRequest().getUrl());
return SaOAuth2Handle.authorize();
}
// OAuth-Server端处理所有OAuth相关请求
@RequestMapping("/oauth2/token")
public Object token() {
System.out.println("------------进入请求:" + SaHolder.getRequest().getUrl());
return SaOAuth2Handle.token();
}
// OAuth-Server端刷新Token
@RequestMapping("/oauth2/ref")
public Object ref(String refresh_token) {
System.out.println("------------进入请求:" + SaHolder.getRequest().getUrl());
return SaResult.data(
SaOAuth2Util.saOAuth2Template.refreshAccessToken(refresh_token).toLineMap()
);
}
// 隐藏式
@RequestMapping("/oauth2/yc")
public Object yc() {
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
// ------------- 以下都是雷同代码
// 1、构建请求Model TODO 貌似这个RequestAuthModel对象也可以省略掉
RequestAuthModel ra = SaOAuth2Util.generateRequestAuth(req, StpUtil.getLoginId());
// 2、如果尚未登录, 则先去登录
if(StpUtil.isLogin() == false) {
return cfg.notLoginView.get();
}
// 3、判断重定向域名的格式是否合法
boolean isRigh = SaOAuth2Util.isRightUrl(ra.clientId, ra.redirectUri);
if(isRigh == false) {
return cfg.invalidUrlView.apply(ra.clientId, ra.redirectUri);
}
// 4、判断此次申请的Scope该Client是否已经签约
boolean isContract = SaOAuth2Util.isContract(ra.clientId, ra.scope);
if(isContract == false) {
return cfg.invalidScopeView.apply(ra.clientId, ra.scope);
}
// 5、判断此次申请的Scope该用户是否已经授权过了
boolean isGrant = SaOAuth2Util.isGrant(StpUtil.getLoginId(), ra.clientId, ra.scope);
if(isGrant == false) {
// 如果尚未授权,则转到授权页面,开始授权操作
return cfg.confirmView.apply(ra.clientId, ra.scope);
}
// ------------- 以上都是雷同代码
// 6、开始重定向授权下放code
AccessTokenModel at = SaOAuth2Util.generateAccessToken(ra);
String redirectUri = SaOAuth2Util.buildRedirectUri2(ra.redirectUri, at.accessToken, ra.state);
return res.redirect(redirectUri);
}
// 密码式
@RequestMapping("/oauth2/password")
public Object password() {
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
// 1、构建请求Model TODO 貌似这个RequestAuthModel对象也可以省略掉
// RequestAuthModel ra = SaOAuth2Util.generateRequestAuth(req, StpUtil.getLoginId());
String username = req.getParamNotNull("username");
String password = req.getParamNotNull("password");
String clientId = req.getParamNotNull("client_id");
Object retObj = cfg.doLoginHandle.apply(username, password);
if(StpUtil.isLogin() == false) {
return retObj;
}
RequestAuthModel ra = new RequestAuthModel();
ra.clientId = req.getParamNotNull(Param.client_id);
// ra.responseType = req.getParamNotNull(Param.response_type);
// ra.redirectUri = req.getParamNotNull(Param.redirect_uri);
// ra.state = req.getParam(Param.state);
ra.scope = "";// 默认应该为空还是内个呢 SaOAuth2Util.saOAuth2Template.getClientScopeList(clientId);
ra.loginId = StpUtil.getLoginId();
// 6、开始重定向授权下放code TODO 这里需要也生成 ref_token
AccessTokenModel at = SaOAuth2Util.generateAccessToken(ra);
//
return SaResult.data(at);
}
// 凭证式
@RequestMapping("/oauth2/appat")
public Object appat() {
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
String clientId = req.getParamNotNull(Param.client_id);
String scope = req.getParam(Param.scope);
ClientTokenModel ct = SaOAuth2Util.generateClientToken(clientId, scope);
//
return SaResult.data(ct.toLineMap());
}
@Autowired
public void setSaOAuth2Config(SaOAuth2Config saOAuth2Config) {
System.out.println("-----------123 " + saOAuth2Config);
saOAuth2Config.
// 未登录的视图
setNotLoginView(()->{
// return "您暂未登录";
HttpServletRequest request = SpringMVCUtil.getRequest();
HttpServletResponse response = SpringMVCUtil.getResponse();
response.setContentType("text/html");
try {
request.getRequestDispatcher("/login.html").forward(request, response);
} catch (ServletException | IOException e) {
e.printStackTrace();
}
return null;
}).
// 未登录的视图
setConfirmView((clientId, scope)->{
return "本次操作需要授权";
})
// 登录处理函数
.setDoLoginHandle((name, pwd) -> {
if("sa".equals(name) && "123456".equals(pwd)) {
StpUtil.login(10001);
return AjaxJson.getSuccess();
}
return SaResult.error();
})
;
}
// 获取授权码 // 获取授权码
@RequestMapping("/authorize") @RequestMapping("/authorize")
public AjaxJson authorize(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { public AjaxJson authorize(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
@@ -53,17 +217,17 @@ public class OAuth2Controller {
// 打印调试 // 打印调试
System.out.println("应用id=" + authModel.getClientId() + "请求授权,授权类型=" + authModel.getResponseType()); System.out.println("应用id=" + authModel.getClientId() + "请求授权,授权类型=" + authModel.getResponseType());
System.out.println("重定向地址:" + authModel.getRedirectUri()); System.out.println("重定向地址:" + authModel.getRedirectUri());
System.out.println("拼接完成的redirect_uri: " + codeModel.getRedirectUri()); // System.out.println("拼接完成的redirect_uri: " + codeModel.getRedirectUri());
System.out.println("如果用户拒绝授权,则重定向至: " + codeModel.getRejectUri()); // System.out.println("如果用户拒绝授权,则重定向至: " + codeModel.getRejectUri());
// 如果请求的权限用户已经确认,直接开始重定向授权 // 如果请求的权限用户已经确认,直接开始重定向授权
if(codeModel.getIsConfirm() == true) { // if(codeModel.getIsConfirm() == true) {
response.sendRedirect(codeModel.getRedirectUri()); // response.sendRedirect(codeModel.getRedirectUri());
} else { // } else {
// 如果请求的权限用户尚未确认,则进入到确定页 // // 如果请求的权限用户尚未确认,则进入到确定页
request.setAttribute("name", "sdd"); // request.setAttribute("name", "sdd");
response.sendRedirect("/auth.html?code=" + codeModel.getCode()); // response.sendRedirect("/auth.html?code=" + codeModel.getCode());
} // }
return AjaxJson.getSuccess(); return AjaxJson.getSuccess();
} }
@@ -92,7 +256,7 @@ public class OAuth2Controller {
return AjaxJson.getError("暂无权限"); return AjaxJson.getError("暂无权限");
} }
// 进行确认 // 进行确认
SaOAuth2Util.confirmCode(code); // SaOAuth2Util.confirmCode(code);
// 返回ok // 返回ok
return AjaxJson.getSuccess(); return AjaxJson.getSuccess();
@@ -108,14 +272,14 @@ public class OAuth2Controller {
String clientSecret = request.getParameter("client_secret"); // 应用秘钥 String clientSecret = request.getParameter("client_secret"); // 应用秘钥
// 校验参数 // 校验参数
SaOAuth2Util.checkCodeIdSecret(code, clientId, clientSecret); // SaOAuth2Util.checkCodeIdSecret(code, clientId, clientSecret);
// 生成 // 生成
CodeModel codeModel = SaOAuth2Util.getCode(code); CodeModel codeModel = SaOAuth2Util.getCode(code);
AccessTokenModel tokenModel = SaOAuth2Util.generateAccessToken(codeModel); AccessTokenModel tokenModel = SaOAuth2Util.generateAccessToken(code);
// 生成AccessToken之后将授权码立即销毁 // 生成AccessToken之后将授权码立即销毁
SaOAuth2Util.deleteCode(code); SaOAuth2Util.deleteCode(code);
// 返回 // 返回
return SoMap.getSoMap() return SoMap.getSoMap()

View File

@@ -0,0 +1,29 @@
package com.pj.oauth2;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
/**
* 注册Bean
*
* @author kong
*
*/
@Component
public class SaOAuth2BeanRegister {
/**
* 获取OAuth2配置Bean
*
* @return 配置对象
*/
@Bean
@ConfigurationProperties(prefix = "sa-token.oauth2")
public SaOAuth2Config getSaOAuth2Config() {
return new SaOAuth2Config();
}
}

View File

@@ -1,8 +1,6 @@
package com.pj.oauth2; package com.pj.oauth2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import cn.dev33.satoken.oauth2.SaOAuth2Manager; import cn.dev33.satoken.oauth2.SaOAuth2Manager;
@@ -19,17 +17,6 @@ import cn.dev33.satoken.oauth2.logic.SaOAuth2Util;
@Component @Component
public class SaOAuth2SpringAutowired { public class SaOAuth2SpringAutowired {
/**
* 获取OAuth2配置Bean
*
* @return 配置对象
*/
@Bean
@ConfigurationProperties(prefix = "sa-token.oauth2")
public SaOAuth2Config getSaOAuth2Config() {
return new SaOAuth2Config();
}
/** /**
* 注入OAuth2配置Bean * 注入OAuth2配置Bean
* *
@@ -50,5 +37,4 @@ public class SaOAuth2SpringAutowired {
SaOAuth2Util.saOAuth2Template = saOAuth2Interface; SaOAuth2Util.saOAuth2Template = saOAuth2Interface;
} }
} }

View File

@@ -99,6 +99,9 @@ public class SaTokenDaoRedisJackson implements SaTokenDao {
*/ */
@Override @Override
public void set(String key, String value, long timeout) { public void set(String key, String value, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期 // 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) { if(timeout == SaTokenDao.NEVER_EXPIRE) {
stringRedisTemplate.opsForValue().set(key, value); stringRedisTemplate.opsForValue().set(key, value);
@@ -170,6 +173,9 @@ public class SaTokenDaoRedisJackson implements SaTokenDao {
*/ */
@Override @Override
public void setObject(String key, Object object, long timeout) { public void setObject(String key, Object object, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期 // 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) { if(timeout == SaTokenDao.NEVER_EXPIRE) {
objectRedisTemplate.opsForValue().set(key, object); objectRedisTemplate.opsForValue().set(key, object);

View File

@@ -79,6 +79,9 @@ public class SaTokenDaoRedis implements SaTokenDao {
*/ */
@Override @Override
public void set(String key, String value, long timeout) { public void set(String key, String value, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期 // 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) { if(timeout == SaTokenDao.NEVER_EXPIRE) {
stringRedisTemplate.opsForValue().set(key, value); stringRedisTemplate.opsForValue().set(key, value);
@@ -149,6 +152,9 @@ public class SaTokenDaoRedis implements SaTokenDao {
*/ */
@Override @Override
public void setObject(String key, Object object, long timeout) { public void setObject(String key, Object object, long timeout) {
if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) {
return;
}
// 判断是否为永不过期 // 判断是否为永不过期
if(timeout == SaTokenDao.NEVER_EXPIRE) { if(timeout == SaTokenDao.NEVER_EXPIRE) {
objectRedisTemplate.opsForValue().set(key, object); objectRedisTemplate.opsForValue().set(key, object);

View File

@@ -1,5 +1,12 @@
package cn.dev33.satoken.oauth2.config; package cn.dev33.satoken.oauth2.config;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.util.SaResult;
/** /**
* sa-token oauth2 配置类 Model * sa-token oauth2 配置类 Model
* @author kong * @author kong
@@ -22,6 +29,11 @@ public class SaOAuth2Config {
*/ */
private long refreshTokenTimeout = 60 * 60 * 24 * 30; private long refreshTokenTimeout = 60 * 60 * 24 * 30;
/**
* client_token默认保存的时间(单位秒) 默认两个小时
*/
private long clientTokenTimeout = 60 * 60 * 2;
/** /**
* @return codeTimeout * @return codeTimeout
@@ -71,9 +83,121 @@ public class SaOAuth2Config {
return this; return this;
} }
/**
* @return clientTokenTimeout
*/
public long getClientTokenTimeout() {
return clientTokenTimeout;
}
/**
* @param clientTokenTimeout 要设置的 clientTokenTimeout
* @return 对象自身
*/
public SaOAuth2Config setClientTokenTimeout(long clientTokenTimeout) {
this.clientTokenTimeout = clientTokenTimeout;
return this;
}
// -------------------- SaOAuth2Handle 所有回调函数 --------------------
/**
* OAuth-Server端未登录时返回的View
*/
public Supplier<Object> notLoginView = () -> "当前会话在OAuth-Server认证中心尚未登录";
/**
* OAuth-Server端重定向URL无效时返回的View
*/
public BiFunction<String, String, Object> invalidUrlView = (clientId, url) -> "无效重定向URL" + url;
/**
* OAuth-Server端Client请求的Scope暂未签约时返回的View
*/
public BiFunction<String, String, Object> invalidScopeView = (clientId, scope) -> "请求的Scope暂未签约";
/**
* OAuth-Server端确认授权时返回的View
*/
public BiFunction<String, String, Object> confirmView = (clientId, scope) -> "本次操作需要用户授权";
/**
* OAuth-Server端登录函数
*/
public BiFunction<String, String, Object> doLoginHandle = (name, pwd) -> SaResult.error();
/**
* SSO-Client端发送Http请求的处理函数
*/
public Function<String, Object> sendHttp = url -> {throw new SaTokenException("请配置Http处理器");};
/**
* @param notLoginView OAuth-Server端未登录时返回的View
* @return 对象自身
*/
public SaOAuth2Config setNotLoginView(Supplier<Object> notLoginView) {
this.notLoginView = notLoginView;
return this;
}
/**
* @param invalidScopeView OAuth-Server端重定向URL无效时返回的View
* @return 对象自身
*/
public SaOAuth2Config setInvalidUrlView(BiFunction<String, String, Object> invalidUrlView) {
this.invalidUrlView = invalidUrlView;
return this;
}
/**
* @param invalidScopeView OAuth-Server端Client请求的Scope暂未签约时返回的View
* @return 对象自身
*/
public SaOAuth2Config setInvalidScopeView(BiFunction<String, String, Object> invalidScopeView) {
this.invalidScopeView = invalidScopeView;
return this;
}
/**
* @param confirmView OAuth-Server端确认授权时返回的View
* @return 对象自身
*/
public SaOAuth2Config setConfirmView(BiFunction<String, String, Object> confirmView) {
this.confirmView = confirmView;
return this;
}
/**
* @param doLoginHandle OAuth-Server端登录函数
* @return 对象自身
*/
public SaOAuth2Config setDoLoginHandle(BiFunction<String, String, Object> doLoginHandle) {
this.doLoginHandle = doLoginHandle;
return this;
}
/**
* @param sendHttp 发送Http请求的处理函数
* @return 对象自身
*/
public SaOAuth2Config setSendHttp(Function<String, Object> sendHttp) {
this.sendHttp = sendHttp;
return this;
}
@Override
public String toString() {
return "SaOAuth2Config [codeTimeout=" + codeTimeout + ", accessTokenTimeout=" + accessTokenTimeout
+ ", refreshTokenTimeout=" + refreshTokenTimeout + "]";
}
} }

View File

@@ -0,0 +1,35 @@
package cn.dev33.satoken.oauth2.exception;
import cn.dev33.satoken.exception.SaTokenException;
/**
* 一个异常代表OAuth2认证流程错误
*
* @author kong
*/
public class SaOAuth2Exception extends SaTokenException {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 6806129545290130114L;
/**
* 一个异常代表OAuth2认证流程错误
*/
public SaOAuth2Exception(String message) {
super(message);
}
/**
* 如果flag==true则抛出message异常
* @param flag 标记
* @param message 异常信息
*/
public static void throwBy(boolean flag, String message) {
if(flag) {
throw new SaOAuth2Exception(message);
}
}
}

View File

@@ -0,0 +1,92 @@
package cn.dev33.satoken.oauth2.logic;
/**
* Sa-Token-OAuth2 所有常量
* @author kong
*
*/
public class SaOAuth2Consts {
/**
* 所有API接口
* @author kong
*/
public static final class Api {
/** OAuth-Server端授权地址 */
public static String authorize = "/oauth2/authorize";
}
/**
* 所有参数名称
* @author kong
*/
public static final class Param {
/** authorize 的 返回值类型 */
public static String response_type = "response_type";
/** client_id 参数名称 */
public static String client_id = "client_id";
/** client_secret 参数名称 */
public static String client_secret = "client_secret";
/** redirect_uri 参数名称 */
public static String redirect_uri = "redirect_uri";
/** scope 参数名称 */
public static String scope = "scope";
/** state */
public static String state = "state";
/** code 参数名称 */
public static String code = "code";
/** token 参数名称 */
public static String token = "token";
/** grant_type 参数名称 */
public static String grant_type = "grant_type";
}
/**
* 所有授权类型
*/
public static final class AuthType {
/** 方式一:授权码 */
public static String code = "code";
/** 方式二:隐藏式 */
public static String token = "token";
/** 方式三:密码式 */
public static String password = "password";
/** 方式四:凭证式 */
public static String client_credentials = "client_credentials";
public static String authorization_code = "authorization_code";
}
/**
* 在保存授权码时用到的key
*/
public static final String UNLIMITED_DOMAIN = "*";
/** 表示OK的返回结果 */
public static final String OK = "ok";
/** 表示请求没有得到任何有效处理 */
public static final String NOT_HANDLE = "not handle";
}

View File

@@ -0,0 +1,125 @@
package cn.dev33.satoken.oauth2.logic;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.AuthType;
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Param;
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
/**
* Sa-Token-OAuth2 请求处理类封装
* @author kong
*
*/
public class SaOAuth2Handle {
/**
* 处理Server端请求
* @return 处理结果
*/
public static Object authorize() {
// 获取变量
SaRequest req = SaHolder.getRequest();
SaResponse res = SaHolder.getResponse();
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
// StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;
// match(Api.authorize) &&
// 授权
if(req.isParam(Param.response_type, AuthType.code)) {
// 1、构建请求Model TODO 貌似这个RequestAuthModel对象也可以省略掉
RequestAuthModel ra = SaOAuth2Util.generateRequestAuth(req, StpUtil.getLoginId());
// 2、如果尚未登录, 则先去登录
if(StpUtil.isLogin() == false) {
return cfg.notLoginView.get();
}
// 3、判断重定向域名的格式是否合法
boolean isRigh = SaOAuth2Util.isRightUrl(ra.clientId, ra.redirectUri);
if(isRigh == false) {
return cfg.invalidUrlView.apply(ra.clientId, ra.redirectUri);
}
// 4、判断此次申请的Scope该Client是否已经签约
boolean isContract = SaOAuth2Util.isContract(ra.clientId, ra.scope);
if(isContract == false) {
return cfg.invalidScopeView.apply(ra.clientId, ra.scope);
}
// 5、判断此次申请的Scope该用户是否已经授权过了
boolean isGrant = SaOAuth2Util.isGrant(StpUtil.getLoginId(), ra.clientId, ra.scope);
if(isGrant == false) {
// 如果尚未授权,则转到授权页面,开始授权操作
return cfg.confirmView.apply(ra.clientId, ra.scope);
}
// 6、开始重定向授权下放code
CodeModel codeModel = SaOAuth2Util.generateCode(ra);
String redirectUri = SaOAuth2Util.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
return res.redirect(redirectUri);
}
// 默认返回
return SaOAuth2Consts.NOT_HANDLE;
}
/**
* 获取Token
* @return
*/
public static Object token() {
// 获取变量
SaRequest req = SaHolder.getRequest();
// SaResponse res = SaHolder.getResponse();
// SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
// 根据code换token
if(req.isParam(Param.grant_type, AuthType.authorization_code)) {
System.out.println("------------获取token");
// 获取参数
String code = req.getParamNotNull(Param.code); // code码
String clientId = req.getParamNotNull(Param.client_id); // 应用id
String clientSecret = req.getParamNotNull(Param.client_secret); // 应用秘钥
String redirectUri = req.getParam(Param.redirect_uri); // 应用秘钥
// 校验参数
SaOAuth2Util.checkCodeIdSecret(code, clientId, clientSecret, redirectUri);
// 构建 access_token
AccessTokenModel token = SaOAuth2Util.generateAccessToken(code);
// 返回
return SaResult.data(token.toLineMap());
}
// 默认返回
return SaOAuth2Consts.NOT_HANDLE;
}
/**
* 路由匹配算法
* @param pattern 路由表达式
* @return 是否可以匹配
*/
static boolean match(String pattern) {
return SaRouter.isMatch(pattern, SaHolder.getRequest().getRequestPath());
}
}

View File

@@ -2,8 +2,11 @@ package cn.dev33.satoken.oauth2.logic;
import java.util.List; import java.util.List;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.oauth2.model.AccessTokenModel; import cn.dev33.satoken.oauth2.model.AccessTokenModel;
import cn.dev33.satoken.oauth2.model.ClientTokenModel;
import cn.dev33.satoken.oauth2.model.CodeModel; import cn.dev33.satoken.oauth2.model.CodeModel;
import cn.dev33.satoken.oauth2.model.RefreshTokenModel;
import cn.dev33.satoken.oauth2.model.RequestAuthModel; import cn.dev33.satoken.oauth2.model.RequestAuthModel;
/** /**
@@ -14,8 +17,29 @@ import cn.dev33.satoken.oauth2.model.RequestAuthModel;
public class SaOAuth2Util { public class SaOAuth2Util {
public static SaOAuth2Template saOAuth2Template = new SaOAuth2Template(); public static SaOAuth2Template saOAuth2Template = new SaOAuth2Template();
/**
* 根据 SaRequest 对象创建 RequestAuthModel
* @param req SaRequest对象
* @param loginId 账号id
* @return RequestAuthModel对象
*/
public static RequestAuthModel generateRequestAuth(SaRequest req, Object loginId) {
return saOAuth2Template.generateRequestAuth(req, loginId);
}
// ---------------------------------------------- 分界线 -----------------------------------------------------
// ------------------- 获取数据 // ------------------- 获取数据
/** /**
@@ -47,6 +71,15 @@ public class SaOAuth2Util {
// ------------------- 数据校验 // ------------------- 数据校验
/**
* [OK] 判断该Client是否签约了指定的Scope
* @param clientId 应用id
* @param scope 权限
*/
public static boolean isContract(String clientId, String scope) {
return saOAuth2Template.isContract(clientId, scope);
}
/** /**
* 指定 loginId 是否对一个 Client 授权给了指定 Scope * 指定 loginId 是否对一个 Client 授权给了指定 Scope
@@ -60,14 +93,25 @@ public class SaOAuth2Util {
} }
/** /**
* 校验code、clientId、clientSecret 三者是否正确 * [OK] 指定Client使用指定url作为回调地址是否合法
* @param clientId 应用id
* @param url 指定url
* @return 是否合法
*/
public static boolean isRightUrl(String clientId, String url) {
return saOAuth2Template.isRightUrl(clientId, url);
}
/**
* [OK 方法名改一下]校验code、clientId、clientSecret 三者是否正确
* @param code 授权码 * @param code 授权码
* @param clientId 应用id * @param clientId 应用id
* @param clientSecret 秘钥 * @param clientSecret 秘钥
* @param redirectUri 秘钥
* @return CodeModel对象 * @return CodeModel对象
*/ */
public static CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret) { public static CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret, String redirectUri) {
return saOAuth2Template.checkCodeIdSecret(code, clientId, clientSecret); return saOAuth2Template.checkCodeIdSecret(code, clientId, clientSecret, redirectUri);
} }
/** /**
@@ -86,7 +130,7 @@ public class SaOAuth2Util {
// ------------------- 逻辑相关 // ------------------- 逻辑相关
/** /**
* 根据参数生成一个授权码并返回 * [OK] 根据参数生成一个授权码并返回
* @param authModel 请求授权参数Model * @param authModel 请求授权参数Model
* @return 授权码Model * @return 授权码Model
*/ */
@@ -94,6 +138,7 @@ public class SaOAuth2Util {
return saOAuth2Template.generateCode(authModel); return saOAuth2Template.generateCode(authModel);
} }
/** /**
* 根据授权码获得授权码Model * 根据授权码获得授权码Model
* @param code 授权码 * @param code 授权码
@@ -103,23 +148,6 @@ public class SaOAuth2Util {
return saOAuth2Template.getCode(code); return saOAuth2Template.getCode(code);
} }
/**
* 手动更改授权码对象信息
* @param code 授权码
* @param codeModel 授权码Model
*/
public static void updateCode(String code, CodeModel codeModel) {
saOAuth2Template.updateCode(code, codeModel);
}
/**
* 确认授权一个code
* @param code 授权码
*/
public static void confirmCode(String code) {
saOAuth2Template.confirmCode(code);
}
/** /**
* [default] 删除一个授权码 * [default] 删除一个授权码
* @param code 授权码 * @param code 授权码
@@ -129,12 +157,12 @@ public class SaOAuth2Util {
} }
/** /**
* [default] 根据授权码Model生成一个access_token * 根据授权码Model生成一个access_token
* @param codeModel 授权码Model * @param codeModel 授权码Model
* @return AccessTokenModel * @return AccessTokenModel
*/ */
public static AccessTokenModel generateAccessToken(CodeModel codeModel) { public static AccessTokenModel generateAccessToken(String code) {
return saOAuth2Template.generateAccessToken(codeModel); return saOAuth2Template.generateAccessToken(code);
} }
/** /**
@@ -156,32 +184,14 @@ public class SaOAuth2Util {
} }
/** /**
* [default] 根据 refresh_token 获得其Model详细信息 (授权码Model) * [default] 根据 refresh_token 获得其Model详细信息
* @param refreshToken refresh_token * @param refreshToken refresh_token
* @return RefreshToken (授权码Model) * @return RefreshToken
*/ */
public static CodeModel getRefreshToken(String refreshToken) { public static RefreshTokenModel getRefreshToken(String refreshToken) {
return saOAuth2Template.getRefreshToken(refreshToken); return saOAuth2Template.getRefreshToken(refreshToken);
} }
/**
* [default] 获取 access_token 的有效期
* @param accessToken access_token
* @return 有效期
*/
public static long getAccessTokenExpiresIn(String accessToken) {
return saOAuth2Template.getAccessTokenExpiresIn(accessToken);
}
/**
* [default] 获取 refresh_token 的有效期
* @param refreshToken refresh_token
* @return 有效期
*/
public static long getRefreshTokenExpiresIn(String refreshToken) {
return saOAuth2Template.getRefreshTokenExpiresIn(refreshToken);
}
/** /**
* [default] 获取 access_token 所代表的LoginId * [default] 获取 access_token 所代表的LoginId
* @param accessToken access_token * @param accessToken access_token
@@ -191,10 +201,46 @@ public class SaOAuth2Util {
return saOAuth2Template.getLoginIdByAccessToken(accessToken); return saOAuth2Template.getLoginIdByAccessToken(accessToken);
} }
/**
* 构建AccessToken Model (根据RequestAuthModel) 用于隐藏式
* @param ra 请求授权参数Model
* @return 授权码Model
*/
public static AccessTokenModel generateAccessToken(RequestAuthModel ra) {
return saOAuth2Template.generateAccessToken(ra);
}
/**
* 构建ClientToken Model
* @param ra 请求授权参数Model
* @return ClientToken-Model
*/
public static ClientTokenModel generateClientToken(String clientId, String scope) {
return saOAuth2Template.generateClientToken(clientId, scope);
}
// ------------------- 自定义策略相关
/**
* [OK] 构建URL下放授权码URL
* @param redirectUri 下放地址
* @param code code参数
* @param state state参数
* @return 构建完毕的URL
*/
public static String buildRedirectUri(String redirectUri, String code, String state) {
return saOAuth2Template.buildRedirectUri(redirectUri, code, state);
}
/**
* [OK] 构建URL下放Token URL
* @param redirectUri 下放地址
* @param token token
* @param state state参数
* @return 构建完毕的URL
*/
public static String buildRedirectUri2(String redirectUri, String token, String state) {
return saOAuth2Template.buildRedirectUri2(redirectUri, token, state);
}
} }

View File

@@ -1,5 +1,8 @@
package cn.dev33.satoken.oauth2.model; package cn.dev33.satoken.oauth2.model;
import java.util.LinkedHashMap;
import java.util.Map;
/** /**
* Model: access_token * Model: access_token
* @author kong * @author kong
@@ -10,177 +13,100 @@ public class AccessTokenModel {
/** /**
* access_token 值 * access_token 值
*/ */
private String accessToken; public String accessToken;
/** /**
* refresh_token 值 * refresh_token 值
*/ */
private String refreshToken; public String refreshToken;
/** /**
* access_token 剩余有效时间 (秒) * access_token 到期时间
*/ */
private long expiresIn; public long expiresTime;
/** /**
* refresh_token 剩余有效期 (秒) * refresh_token 到期时间
*/ */
private long refreshExpiresIn; public long refreshExpiresTime;
/**
* 此 access_token令牌 是由哪个code码创建
*/
private String code;
/** /**
* 应用id * 应用id
*/ */
private String clientId; public String clientId;
/**
* 授权范围
*/
private String scope;
/**
* 账号id
*/
public Object loginId;
/** /**
* 开放账号id * 开放账号id
*/ */
private String openid; public String openid;
/** /**
* 其他自定义数据 * 授权范围
*/ */
private Object tag; public String scope;
public AccessTokenModel() {}
/** /**
* @return accessToken * 构建一个
* @param accessToken accessToken
* @param clientId 应用id
* @param scope 请求授权范围
* @param loginId 对应的账号id
*/ */
public String getAccessToken() { public AccessTokenModel(String accessToken, String clientId, Object loginId, String scope) {
return accessToken; super();
}
/**
* @param accessToken 要设置的 accessToken
*/
public void setAccessToken(String accessToken) {
this.accessToken = accessToken; this.accessToken = accessToken;
}
/**
* @return refreshToken
*/
public String getRefreshToken() {
return refreshToken;
}
/**
* @param refreshToken 要设置的 refreshToken
*/
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
/**
* @return expiresIn
*/
public long getExpiresIn() {
return expiresIn;
}
/**
* @param expiresIn 要设置的 expiresIn
*/
public void setExpiresIn(long expiresIn) {
this.expiresIn = expiresIn;
}
/**
* @return refreshExpiresIn
*/
public long getRefreshExpiresIn() {
return refreshExpiresIn;
}
/**
* @param refreshExpiresIn 要设置的 refreshExpiresIn
*/
public void setRefreshExpiresIn(long refreshExpiresIn) {
this.refreshExpiresIn = refreshExpiresIn;
}
/**
* @return code
*/
public String getCode() {
return code;
}
/**
* @param code 要设置的 code
*/
public void setCode(String code) {
this.code = code;
}
/**
* @return clientId
*/
public String getClientId() {
return clientId;
}
/**
* @param clientId 要设置的 clientId
*/
public void setClientId(String clientId) {
this.clientId = clientId; this.clientId = clientId;
} this.loginId = loginId;
/**
* @return scope
*/
public String getScope() {
return scope;
}
/**
* @param scope 要设置的 scope
*/
public void setScope(String scope) {
this.scope = scope; this.scope = scope;
} }
@Override
public String toString() {
return "AccessTokenModel [accessToken=" + accessToken + ", refreshToken=" + refreshToken
+ ", accessTokenTimeout=" + expiresTime + ", refreshTokenTimeout=" + refreshExpiresTime
+ ", clientId=" + clientId + ", scope=" + scope + ", openid=" + openid + "]";
}
/** /**
* @return openid * 获取:此 Access-Token 的剩余有效期(秒)
* @return see note
*/ */
public String getOpenid() { public long getExpiresIn() {
return openid; long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
} }
/** /**
* @param openid 要设置的 openid * 获取:此 Refresh-Token 的剩余有效期(秒)
* @return see note
*/ */
public void setOpenid(String openid) { public long getRefreshExpiresIn() {
this.openid = openid; long s = (refreshExpiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
} }
/**
* @return tag
*/
public Object getTag() {
return tag;
}
/**
* @param tag 要设置的 tag
*/
public void setTag(Object tag) {
this.tag = tag;
}
/**
* 将所有属性转换为下划线形式的Map
* @return
*/
public Map<String, Object> toLineMap() {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("access_token", accessToken);
map.put("refresh_token", refreshToken);
map.put("expires_in", getExpiresIn());
map.put("refresh_expires_in", getRefreshExpiresIn());
map.put("client_id", clientId);
map.put("scope", scope);
map.put("openid", openid);
return map;
}
} }

View File

@@ -0,0 +1,78 @@
package cn.dev33.satoken.oauth2.model;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Model: client_token
* @author kong
*
*/
public class ClientTokenModel {
/**
* client_token 值
*/
public String clientToken;
/**
* client_token 到期时间
*/
public long expiresTime;
/**
* 应用id
*/
public String clientId;
/**
* 授权范围
*/
public String scope;
public ClientTokenModel() {}
/**
* 构建一个
* @param accessToken accessToken
* @param clientId 应用id
* @param scope 请求授权范围
* @param loginId 对应的账号id
*/
public ClientTokenModel(String accessToken, String clientId, String scope) {
super();
this.clientToken = accessToken;
this.clientId = clientId;
this.scope = scope;
}
@Override
public String toString() {
return "ClientTokenModel [clientToken=" + clientToken + ", expiresTime=" + expiresTime + ", clientId="
+ clientId + ", scope=" + scope + "]";
}
/**
* 获取:此 Client-Token 的剩余有效期(秒)
* @return see note
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
/**
* 将所有属性转换为下划线形式的Map
* @return
*/
public Map<String, Object> toLineMap() {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("client_token", clientToken);
map.put("expires_in", getExpiresIn());
map.put("client_id", clientId);
map.put("scope", scope);
return map;
}
}

View File

@@ -7,48 +7,31 @@ package cn.dev33.satoken.oauth2.model;
*/ */
public class CodeModel { public class CodeModel {
/** /**
* 授权码 * 授权码
*/ */
private String code; public String code;
/** /**
* 应用id * 应用id
*/ */
private String clientId; public String clientId;
/** /**
* 授权范围 * 授权范围
*/ */
private String scope; public String scope;
/** /**
* 对应账号id * 对应账号id
*/ */
private Object loginId; public Object loginId;
/** /**
* 用户是否已经确认了这个授权 * 重定向的地址
*/ */
private Boolean isConfirm; public String redirectUri;
/**
* 确认授权后重定向的地址
*/
private String redirectUri;
/**
* 拒绝授权后重定向的地址
*/
private String rejectUri;
/**
* 其他自定义数据
*/
private Object tag;
/** /**
* 构建一个 * 构建一个
*/ */
@@ -62,16 +45,15 @@ public class CodeModel {
* @param scope 请求授权范围 * @param scope 请求授权范围
* @param loginId 对应的账号id * @param loginId 对应的账号id
*/ */
public CodeModel(String code, String clientId, String scope, Object loginId) { public CodeModel(String code, String clientId, String scope, Object loginId, String redirectUri) {
super(); super();
this.code = code; this.code = code;
this.clientId = clientId; this.clientId = clientId;
this.scope = scope; this.scope = scope;
this.loginId = loginId; this.loginId = loginId;
this.isConfirm = false; this.redirectUri = redirectUri;
} }
/** /**
* @return code * @return code
@@ -128,21 +110,7 @@ public class CodeModel {
public void setLoginId(Object loginId) { public void setLoginId(Object loginId) {
this.loginId = loginId; this.loginId = loginId;
} }
/**
* @return isConfirm
*/
public Boolean getIsConfirm() {
return isConfirm;
}
/**
* @param isConfirm 要设置的 isConfirm
*/
public void setIsConfirm(Boolean isConfirm) {
this.isConfirm = isConfirm;
}
/** /**
* @return redirectUri * @return redirectUri
*/ */
@@ -156,36 +124,11 @@ public class CodeModel {
public void setRedirectUri(String redirectUri) { public void setRedirectUri(String redirectUri) {
this.redirectUri = redirectUri; this.redirectUri = redirectUri;
} }
/** @Override
* @return rejectUri public String toString() {
*/ return "CodeModel [code=" + code + ", clientId=" + clientId + ", scope=" + scope + ", loginId=" + loginId
public String getRejectUri() { + ", redirectUri=" + redirectUri + "]";
return rejectUri;
} }
/**
* @param rejectUri 要设置的 rejectUri
*/
public void setRejectUri(String rejectUri) {
this.rejectUri = rejectUri;
}
/**
* @return tag
*/
public Object getTag() {
return tag;
}
/**
* @param tag 要设置的 tag
*/
public void setTag(Object tag) {
this.tag = tag;
}
} }

View File

@@ -0,0 +1,54 @@
package cn.dev33.satoken.oauth2.model;
/**
* Model: refresh_token
* @author kong
*
*/
public class RefreshTokenModel {
/**
* refresh_token 值
*/
public String refreshToken;
/**
* refresh_token到期时间
*/
public long expiresTime;
/**
* 应用id
*/
public String clientId;
/**
* 授权范围
*/
public String scope;
/**
* 对应账号id
*/
public Object loginId;
/**
* 对应账号id
*/
public String openid;
@Override
public String toString() {
return "RefreshTokenModel [refreshToken=" + refreshToken + ", expiresTime=" + expiresTime
+ ", clientId=" + clientId + ", scope=" + scope + ", loginId=" + loginId + ", openid=" + openid + "]";
}
/**
* 获取:此 Refresh-Token 的剩余有效期(秒)
* @return see note
*/
public long getExpiresIn() {
long s = (expiresTime - System.currentTimeMillis()) / 1000;
return s < 1 ? -2 : s;
}
}

View File

@@ -13,32 +13,32 @@ public class RequestAuthModel {
/** /**
* 应用id * 应用id
*/ */
private String clientId; public String clientId;
/** /**
* 授权范围 * 授权范围
*/ */
private String scope; public String scope;
/** /**
* 对应的账号id * 对应的账号id
*/ */
private Object loginId; public Object loginId;
/** /**
* 待重定向URL * 待重定向URL
*/ */
private String redirectUri; public String redirectUri;
/** /**
* 授权类型, 非必填 * 授权类型, 非必填
*/ */
private String responseType; public String responseType;
/** /**
* 状态标识, 可为null * 状态标识, 可为null
*/ */
private String state; public String state;
/** /**
@@ -156,5 +156,6 @@ public class RequestAuthModel {
} }
return this; return this;
} }
} }

View File

@@ -1,73 +1,73 @@
package cn.dev33.satoken.oauth2.model; //package cn.dev33.satoken.oauth2.model;
//
/** ///**
* 权限Model // * 权限Model
* @author kong // * @author kong
* // *
*/ // */
public class ScopeModel { //public class ScopeModel {
//
/** // /**
* 权限名称 // * 权限名称
*/ // */
private String name; // private String name;
//
/** // /**
* 详细介绍 // * 详细介绍
*/ // */
private String introduce; // private String introduce;
//
//
/** // /**
* 构造一个 // * 构造一个
*/ // */
public ScopeModel() { // public ScopeModel() {
super(); // super();
} // }
/** // /**
* 构造一个 // * 构造一个
* @param name 权限名称 // * @param name 权限名称
* @param introduce 权限详细介绍 // * @param introduce 权限详细介绍
*/ // */
public ScopeModel(String name, String introduce) { // public ScopeModel(String name, String introduce) {
super(); // super();
this.name = name; // this.name = name;
this.introduce = introduce; // this.introduce = introduce;
} // }
//
/** // /**
* @return name // * @return name
*/ // */
public String getName() { // public String getName() {
return name; // return name;
} // }
//
/** // /**
* @param name 要设置的 name // * @param name 要设置的 name
*/ // */
public void setName(String name) { // public void setName(String name) {
this.name = name; // this.name = name;
} // }
//
/** // /**
* @return introduce // * @return introduce
*/ // */
public String getIntroduce() { // public String getIntroduce() {
return introduce; // return introduce;
} // }
//
/** // /**
* @param introduce 要设置的 introduce // * @param introduce 要设置的 introduce
*/ // */
public void setIntroduce(String introduce) { // public void setIntroduce(String introduce) {
this.introduce = introduce; // this.introduce = introduce;
} // }
//
//
//
//
//
//
//
//
} //}

View File

@@ -1,15 +0,0 @@
package cn.dev33.satoken.oauth2.util;
/**
* sa-token oauth2 模块 用到的所有常量
* @author kong
*
*/
public class SaOAuth2Consts {
/**
* 在保存授权码时用到的key
*/
public static final String UNLIMITED_DOMAIN = "*";
}

View File

@@ -38,7 +38,7 @@ public class SaRequestForReactor implements SaRequest {
* 在 [请求体] 里获取一个值 * 在 [请求体] 里获取一个值
*/ */
@Override @Override
public String getParameter(String name) { public String getParam(String name) {
return request.getQueryParams().getFirst(name); return request.getQueryParams().getFirst(name);
} }

View File

@@ -37,7 +37,7 @@ public class SaRequestForServlet implements SaRequest {
* 在 [请求体] 里获取一个值 * 在 [请求体] 里获取一个值
*/ */
@Override @Override
public String getParameter(String name) { public String getParam(String name) {
return request.getParameter(name); return request.getParameter(name);
} }

View File

@@ -21,7 +21,7 @@ public class SaRequestForSolon implements SaRequest {
} }
@Override @Override
public String getParameter(String s) { public String getParam(String s) {
return ctx.param(s); return ctx.param(s);
} }