diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java index 22173ee8..76b7dfa6 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/context/model/SaRequest.java @@ -1,5 +1,6 @@ package cn.dev33.satoken.context.model; +import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.util.SaFoxUtil; /** @@ -20,7 +21,7 @@ public interface SaRequest { * @param name 键 * @return 值 */ - public String getParameter(String name); + public String getParam(String name); /** * 在 [请求体] 里获取一个值,值为空时返回默认值 @@ -28,14 +29,39 @@ public interface SaRequest { * @param defaultValue 值为空时的默认值 * @return 值 */ - public default String getParameter(String name, String defaultValue) { - String value = getParameter(name); + public default String getParam(String name, String defaultValue) { + String value = getParam(name); if(SaFoxUtil.isEmpty(value)) { return defaultValue; } 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 键 diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java index 8f771f9b..6a0293fc 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDao.java @@ -30,7 +30,7 @@ public interface SaTokenDao { * 写入Value,并设定存活时间 (单位: 秒) * @param key 键名称 * @param value 值 - * @param timeout 过期时间 + * @param timeout 过期时间(值>0时限时存储,值=-1时永久存储,值=0或<=-2时不存储) */ public void set(String key, String value, long timeout); @@ -75,7 +75,7 @@ public interface SaTokenDao { * 写入Object,并设定存活时间 (单位: 秒) * @param key 键名称 * @param object 值 - * @param timeout 存活时间 + * @param timeout 存活时间 (值>0时限时存储,值=-1时永久存储,值=0或<=-2时不存储) */ public void setObject(String key, Object object, long timeout); diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java index 2e4ddd99..81839c61 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/dao/SaTokenDaoDefaultImpl.java @@ -45,6 +45,9 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao { @Override public void set(String key, String value, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } dataMap.put(key, value); expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); } @@ -84,6 +87,9 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao { @Override public void setObject(String key, Object object, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } dataMap.put(key, object); expireMap.put(key, (timeout == SaTokenDao.NEVER_EXPIRE) ? (SaTokenDao.NEVER_EXPIRE) : (System.currentTimeMillis() + timeout * 1000)); } diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java index 75370f5d..f1c2ff16 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/sso/SaSsoHandle.java @@ -39,19 +39,19 @@ public class SaSsoHandle { return sso.notLoginView.get(); } // 情况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); } // ---------- SSO-Server端:RestAPI 登录接口 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 if(match(Api.ssoCheckTicket) && sso.isHttp) { - String ticket = req.getParameter(ParamName.ticket); - String sloCallback = req.getParameter(ParamName.ssoLogoutCall); + String ticket = req.getParam(ParamName.ticket); + String sloCallback = req.getParam(ParamName.ssoLogoutCall); // 校验ticket,获取对应的账号id Object loginId = SaSsoUtil.checkTicket(ticket); @@ -65,8 +65,8 @@ public class SaSsoHandle { // ---------- SSO-Server端:单点注销 if(match(Api.ssoLogout) && sso.isSlo) { - String loginId = req.getParameter(ParamName.loginId); - String secretkey = req.getParameter(ParamName.secretkey); + String loginId = req.getParam(ParamName.loginId); + String secretkey = req.getParam(ParamName.secretkey); // 遍历通知Client端注销会话 SaSsoUtil.singleLogout(secretkey, loginId, url -> sso.sendHttp.apply(url)); @@ -93,8 +93,8 @@ public class SaSsoHandle { // ---------- SSO-Client端:登录地址 if(match(Api.ssoLogin)) { - String back = req.getParameter(ParamName.back, "/"); - String ticket = req.getParameter(ParamName.ticket); + String back = req.getParam(ParamName.back, "/"); + String ticket = req.getParam(ParamName.ticket); // 如果当前Client端已经登录,则无需访问SSO认证中心,可以直接返回 if(stpLogic.isLogin()) { @@ -138,10 +138,10 @@ public class SaSsoHandle { // ---------- SSO-Client端:单点注销 [模式二] if(match(Api.ssoLogout) && sso.isSlo && sso.isHttp == false) { stpLogic.logout(); - if(req.getParameter(ParamName.back) == null) { + if(req.getParam(ParamName.back) == null) { return SaResult.ok("单点注销成功"); } 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 body = String.valueOf(sso.sendHttp.apply(url)); if(SaSsoConsts.OK.equals(body)) { - if(req.getParameter(ParamName.back) == null) { + if(req.getParam(ParamName.back) == null) { return SaResult.ok("单点注销成功"); } else { - return res.redirect(req.getParameter(ParamName.back, "/")); + return res.redirect(req.getParam(ParamName.back, "/")); } } return SaResult.error("单点注销失败"); @@ -166,8 +166,8 @@ public class SaSsoHandle { // ---------- SSO-Client端:单点注销的回调 [模式三] if(match(Api.ssoLogoutCall) && sso.isSlo && sso.isHttp) { - String loginId = req.getParameter(ParamName.loginId); - String secretkey = req.getParameter(ParamName.secretkey); + String loginId = req.getParam(ParamName.loginId); + String secretkey = req.getParam(ParamName.secretkey); SaSsoUtil.checkSecretkey(secretkey); stpLogic.logoutByTokenValue(stpLogic.getTokenValueByLoginId(loginId)); diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java index f898eb83..31bf516a 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/stp/StpLogic.java @@ -132,7 +132,7 @@ public class StpLogic { } // 2. 尝试从请求体里面读取 if(tokenValue == null && config.getIsReadBody()){ - tokenValue = request.getParameter(keyTokenName); + tokenValue = request.getParam(keyTokenName); } // 3. 尝试从header里读取 if(tokenValue == null && config.getIsReadHead()){ diff --git a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java index b2c85029..6cdf98dc 100644 --- a/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java +++ b/sa-token-core/src/main/java/cn/dev33/satoken/util/SaFoxUtil.java @@ -204,7 +204,7 @@ public class SaFoxUtil { if(url == null) { url = ""; } - int index = url.indexOf('?'); + int index = url.lastIndexOf('?'); // ? 不存在 if(index == -1) { return url + '?' + parameStr; @@ -236,11 +236,63 @@ public class SaFoxUtil { */ 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 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); + } /** * 将数组的所有元素使用逗号拼接在一起 diff --git a/sa-token-demo/sa-token-demo-oauth2-server/pom.xml b/sa-token-demo/sa-token-demo-oauth2-server/pom.xml index 99f4ff6d..fac12aca 100644 --- a/sa-token-demo/sa-token-demo-oauth2-server/pom.xml +++ b/sa-token-demo/sa-token-demo-oauth2-server/pom.xml @@ -43,7 +43,7 @@ - + diff --git a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java index 00eccc07..efc37def 100644 --- a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java +++ b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/SaOAuth2ServerApplication.java @@ -12,7 +12,7 @@ public class SaOAuth2ServerApplication { public static void main(String[] args) { SpringApplication.run(SaOAuth2ServerApplication.class, args); - System.out.println("\n服务端启动成功"); + System.out.println("\nOAuth-Server端启动成功"); } } diff --git a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/controller/OAuth2Controller.java b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/controller/OAuth2Controller.java index 9d8d6957..d3207634 100644 --- a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/controller/OAuth2Controller.java +++ b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/controller/OAuth2Controller.java @@ -7,23 +7,187 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; 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.RestController; import com.pj.utils.AjaxJson; 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.SaOAuth2Consts.Param; 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.RequestAuthModel; +import cn.dev33.satoken.spring.SpringMVCUtil; import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.util.SaResult; @RestController -@RequestMapping("/oauth2/") +//@RequestMapping("/oauth2/") 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") 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("重定向地址:" + authModel.getRedirectUri()); - System.out.println("拼接完成的redirect_uri: " + codeModel.getRedirectUri()); - System.out.println("如果用户拒绝授权,则重定向至: " + codeModel.getRejectUri()); + // System.out.println("拼接完成的redirect_uri: " + codeModel.getRedirectUri()); + // System.out.println("如果用户拒绝授权,则重定向至: " + codeModel.getRejectUri()); // 如果请求的权限用户已经确认,直接开始重定向授权 - if(codeModel.getIsConfirm() == true) { - response.sendRedirect(codeModel.getRedirectUri()); - } else { - // 如果请求的权限用户尚未确认,则进入到确定页 - request.setAttribute("name", "sdd"); - response.sendRedirect("/auth.html?code=" + codeModel.getCode()); - } +// if(codeModel.getIsConfirm() == true) { +// response.sendRedirect(codeModel.getRedirectUri()); +// } else { +// // 如果请求的权限用户尚未确认,则进入到确定页 +// request.setAttribute("name", "sdd"); +// response.sendRedirect("/auth.html?code=" + codeModel.getCode()); +// } return AjaxJson.getSuccess(); } @@ -92,7 +256,7 @@ public class OAuth2Controller { return AjaxJson.getError("暂无权限"); } // 进行确认 - SaOAuth2Util.confirmCode(code); + // SaOAuth2Util.confirmCode(code); // 返回ok return AjaxJson.getSuccess(); @@ -108,14 +272,14 @@ public class OAuth2Controller { String clientSecret = request.getParameter("client_secret"); // 应用秘钥 // 校验参数 - SaOAuth2Util.checkCodeIdSecret(code, clientId, clientSecret); + // SaOAuth2Util.checkCodeIdSecret(code, clientId, clientSecret); // 生成 CodeModel codeModel = SaOAuth2Util.getCode(code); - AccessTokenModel tokenModel = SaOAuth2Util.generateAccessToken(codeModel); + AccessTokenModel tokenModel = SaOAuth2Util.generateAccessToken(code); // 生成AccessToken之后,将授权码立即销毁 - SaOAuth2Util.deleteCode(code); + SaOAuth2Util.deleteCode(code); // 返回 return SoMap.getSoMap() diff --git a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2BeanRegister.java b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2BeanRegister.java new file mode 100644 index 00000000..d7c23503 --- /dev/null +++ b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2BeanRegister.java @@ -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(); + } + +} diff --git a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2SpringAutowired.java b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2SpringAutowired.java index c1344af6..30003b87 100644 --- a/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2SpringAutowired.java +++ b/sa-token-demo/sa-token-demo-oauth2-server/src/main/java/com/pj/oauth2/SaOAuth2SpringAutowired.java @@ -1,8 +1,6 @@ package com.pj.oauth2; 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 cn.dev33.satoken.oauth2.SaOAuth2Manager; @@ -19,17 +17,6 @@ import cn.dev33.satoken.oauth2.logic.SaOAuth2Util; @Component public class SaOAuth2SpringAutowired { - /** - * 获取OAuth2配置Bean - * - * @return 配置对象 - */ - @Bean - @ConfigurationProperties(prefix = "sa-token.oauth2") - public SaOAuth2Config getSaOAuth2Config() { - return new SaOAuth2Config(); - } - /** * 注入OAuth2配置Bean * @@ -50,5 +37,4 @@ public class SaOAuth2SpringAutowired { SaOAuth2Util.saOAuth2Template = saOAuth2Interface; } - } diff --git a/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java b/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java index 0451102d..dc230ec0 100644 --- a/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java +++ b/sa-token-plugin/sa-token-dao-redis-jackson/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedisJackson.java @@ -99,6 +99,9 @@ public class SaTokenDaoRedisJackson implements SaTokenDao { */ @Override public void set(String key, String value, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } // 判断是否为永不过期 if(timeout == SaTokenDao.NEVER_EXPIRE) { stringRedisTemplate.opsForValue().set(key, value); @@ -170,6 +173,9 @@ public class SaTokenDaoRedisJackson implements SaTokenDao { */ @Override public void setObject(String key, Object object, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } // 判断是否为永不过期 if(timeout == SaTokenDao.NEVER_EXPIRE) { objectRedisTemplate.opsForValue().set(key, object); diff --git a/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java b/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java index 43acf598..532f844d 100644 --- a/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java +++ b/sa-token-plugin/sa-token-dao-redis/src/main/java/cn/dev33/satoken/dao/SaTokenDaoRedis.java @@ -79,6 +79,9 @@ public class SaTokenDaoRedis implements SaTokenDao { */ @Override public void set(String key, String value, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } // 判断是否为永不过期 if(timeout == SaTokenDao.NEVER_EXPIRE) { stringRedisTemplate.opsForValue().set(key, value); @@ -149,6 +152,9 @@ public class SaTokenDaoRedis implements SaTokenDao { */ @Override public void setObject(String key, Object object, long timeout) { + if(timeout == 0 || timeout <= SaTokenDao.NOT_VALUE_EXPIRE) { + return; + } // 判断是否为永不过期 if(timeout == SaTokenDao.NEVER_EXPIRE) { objectRedisTemplate.opsForValue().set(key, object); diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java index 5af2c620..de245b7c 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/config/SaOAuth2Config.java @@ -1,5 +1,12 @@ 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 * @author kong @@ -22,6 +29,11 @@ public class SaOAuth2Config { */ private long refreshTokenTimeout = 60 * 60 * 24 * 30; + /** + * client_token默认保存的时间(单位秒) 默认两个小时 + */ + private long clientTokenTimeout = 60 * 60 * 2; + /** * @return codeTimeout @@ -71,9 +83,121 @@ public class SaOAuth2Config { 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 notLoginView = () -> "当前会话在OAuth-Server认证中心尚未登录"; + + /** + * OAuth-Server端:重定向URL无效时返回的View + */ + public BiFunction invalidUrlView = (clientId, url) -> "无效重定向URL:" + url; + + /** + * OAuth-Server端:Client请求的Scope暂未签约时返回的View + */ + public BiFunction invalidScopeView = (clientId, scope) -> "请求的Scope暂未签约"; + + /** + * OAuth-Server端:确认授权时返回的View + */ + public BiFunction confirmView = (clientId, scope) -> "本次操作需要用户授权"; + + /** + * OAuth-Server端:登录函数 + */ + public BiFunction doLoginHandle = (name, pwd) -> SaResult.error(); + + /** + * SSO-Client端:发送Http请求的处理函数 + */ + public Function sendHttp = url -> {throw new SaTokenException("请配置Http处理器");}; + + + /** + * @param notLoginView OAuth-Server端:未登录时返回的View + * @return 对象自身 + */ + public SaOAuth2Config setNotLoginView(Supplier notLoginView) { + this.notLoginView = notLoginView; + return this; + } + + /** + * @param invalidScopeView OAuth-Server端:重定向URL无效时返回的View + * @return 对象自身 + */ + public SaOAuth2Config setInvalidUrlView(BiFunction invalidUrlView) { + this.invalidUrlView = invalidUrlView; + return this; + } + + /** + * @param invalidScopeView OAuth-Server端:Client请求的Scope暂未签约时返回的View + * @return 对象自身 + */ + public SaOAuth2Config setInvalidScopeView(BiFunction invalidScopeView) { + this.invalidScopeView = invalidScopeView; + return this; + } + + /** + * @param confirmView OAuth-Server端:确认授权时返回的View + * @return 对象自身 + */ + public SaOAuth2Config setConfirmView(BiFunction confirmView) { + this.confirmView = confirmView; + return this; + } + + /** + * @param doLoginHandle OAuth-Server端:登录函数 + * @return 对象自身 + */ + public SaOAuth2Config setDoLoginHandle(BiFunction doLoginHandle) { + this.doLoginHandle = doLoginHandle; + return this; + } + + /** + * @param sendHttp 发送Http请求的处理函数 + * @return 对象自身 + */ + public SaOAuth2Config setSendHttp(Function sendHttp) { + this.sendHttp = sendHttp; + return this; + } + - + @Override + public String toString() { + return "SaOAuth2Config [codeTimeout=" + codeTimeout + ", accessTokenTimeout=" + accessTokenTimeout + + ", refreshTokenTimeout=" + refreshTokenTimeout + "]"; + } + } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/exception/SaOAuth2Exception.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/exception/SaOAuth2Exception.java new file mode 100644 index 00000000..44b86e47 --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/exception/SaOAuth2Exception.java @@ -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); + } + } + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Consts.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Consts.java new file mode 100644 index 00000000..5848513f --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Consts.java @@ -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"; + + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java new file mode 100644 index 00000000..6e915100 --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Handle.java @@ -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()); + } +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java index 58fef9fe..e01251da 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Template.java @@ -1,17 +1,20 @@ package cn.dev33.satoken.oauth2.logic; -import java.net.MalformedURLException; -import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.oauth2.SaOAuth2Manager; +import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception; +import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts.Param; 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.RefreshTokenModel; import cn.dev33.satoken.oauth2.model.RequestAuthModel; -import cn.dev33.satoken.oauth2.util.SaOAuth2Consts; import cn.dev33.satoken.util.SaFoxUtil; /** @@ -21,9 +24,7 @@ import cn.dev33.satoken.util.SaFoxUtil; */ public class SaOAuth2Template { - // ------------------- 获取数据 - /** * 返回此平台所有权限集合 * @return 此平台所有权限名称集合 @@ -43,7 +44,7 @@ public class SaOAuth2Template { } /** - * 获取指定 LoginId 对指定 Client 已经授权过的所有 Scope + * [转Redis]获取指定 LoginId 对指定 Client 已经授权过的所有 Scope * @param clientId 应用id * @param loginId 账号id * @return Scope集合 @@ -82,7 +83,7 @@ public class SaOAuth2Template { } /** - * 根据ClientId和openid返回LoginId + * [可取消]根据ClientId和openid返回LoginId * @param clientId 应用id * @param openid openid * @return LoginId @@ -91,24 +92,289 @@ public class SaOAuth2Template { return null; } + // ------------------- conver 数据转换 + /** + * [OK] 将 CodeModel 转换为 AccessTokenModel + * @param cm CodeModel对象 + * @return AccessToken对象 + */ + public AccessTokenModel converCodeToAccessToken(CodeModel cm) { + AccessTokenModel at = new AccessTokenModel(); + at.accessToken = randomAccessToken(cm.clientId, cm.loginId, cm.scope); + at.refreshToken = randomRefreshToken(cm.clientId, cm.loginId, cm.scope); + at.clientId = cm.clientId; + at.loginId = cm.loginId; + at.scope = cm.scope; + at.openid = getOpenid(cm.clientId, cm.loginId); + at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000); + // at.refreshExpiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getRefreshTokenTimeout() * 1000); + return at; + } + /** + * [OK] 将 AccessToken 转换为 RefreshTokenModel + * @param at AccessToken对象 + * @return RefreshToken对象 + */ + public RefreshTokenModel converAccessTokenToRefreshToken(AccessTokenModel at) { + RefreshTokenModel rt = new RefreshTokenModel(); + rt.refreshToken = at.refreshToken; + rt.clientId = at.clientId; + rt.loginId = at.loginId; + rt.scope = at.scope; + rt.openid = at.openid; + rt.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getRefreshTokenTimeout() * 1000); + return rt; + } + /** + * [OK] 将 RefreshTokenModel 转换为 AccessTokenModel + * @param codeModel CodeModel对象 + * @return RefreshToken对象 + */ + public AccessTokenModel converRefreshTokenToAccessToken(RefreshTokenModel rt) { + AccessTokenModel at = new AccessTokenModel(); + at.accessToken = randomAccessToken(rt.clientId, rt.loginId, rt.scope); + at.refreshToken = rt.refreshToken; + at.clientId = rt.clientId; + at.loginId = rt.loginId; + at.scope = rt.scope; + at.openid = rt.openid; + at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000); + at.refreshExpiresTime = rt.expiresTime; + return at; + } + /** + * 将指定字符串按照逗号分隔符转化为字符串集合 + * @param str 字符串 + * @return 分割后的字符串集合 + */ + public List convertStringToList(String str) { + String[] arr = str.split(","); + List list = new ArrayList(); + for (String s : arr) { + if(SaFoxUtil.isEmpty(s) == false) { + list.add(s); + } + } + return list; + } - // ------------------- 数据校验 + // ------------------- generate 构建数据 + /** + * 构建:请求Model + * @param req SaRequest对象 + * @param loginId 账号id + * @return RequestAuthModel对象 + */ + public RequestAuthModel generateRequestAuth(SaRequest req, Object loginId) { + 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 = req.getParam(Param.scope, ""); + ra.loginId = loginId; + return ra; + } + /** + * 构建:授权码Model + * @param ra 请求授权参数Model + * @return 授权码Model + */ + public CodeModel generateCode(RequestAuthModel ra) { + + // 删除旧Code + String oldCode = getCodeValue(ra.clientId, ra.loginId); + if(oldCode != null) { + deleteCode(oldCode); + // deleteCodeIndex(ra.clientId, ra.loginId); // 此处无需删除,因为下边的set会直接覆盖掉 + } + + // 生成新Code + String code = randomCode(ra.clientId, ra.loginId, ra.scope); + CodeModel codeModel = new CodeModel(code, ra.clientId, ra.scope, ra.loginId, ra.redirectUri); + + // 保存新Code + saveCode(codeModel); + saveCodeIndex(codeModel); + + // 返回 + return codeModel; + } + /** + * 构建:AccessToken Model + * @param codeModel 授权码Model + * @return AccessTokenModel + */ + public AccessTokenModel generateAccessToken(String code) { + + // 先校验 + CodeModel cm = getCode(code); + SaOAuth2Exception.throwBy(cm == null, "无效code"); + + // 生成token + AccessTokenModel at = converCodeToAccessToken(cm); + RefreshTokenModel rt = converAccessTokenToRefreshToken(at); + at.refreshExpiresTime = rt.expiresTime; + + // 保存Token + saveAccessToken(at); + saveAccessTokenIndex(at); + saveRefreshToken(rt); + saveRefreshTokenIndex(rt); + + // 删除此Code + deleteCode(code); + deleteCodeIndex(cm.clientId, cm.loginId); + + // 返回 + return at; + } + /** + * 刷新:根据 RefreshToken 生成一个 AccessToken + * @param refreshToken refresh_token + * @return 新的 access_token + */ + public AccessTokenModel refreshAccessToken(String refreshToken) { + + // 获取RefreshToken信息 + RefreshTokenModel rt = getRefreshToken(refreshToken); + SaOAuth2Exception.throwBy(rt == null, "无效refresh_token: " + refreshToken); + + // 删除旧AccessToken + String atValue = getAccessTokenValue(rt.clientId, rt.loginId); + if(atValue != null) { + deleteAccessToken(atValue); + deleteAccessTokenIndex(rt.clientId, rt.loginId); + } + + // 生成新AccessToken + AccessTokenModel at = converRefreshTokenToAccessToken(rt); + + // 保存新AccessToken + saveAccessToken(at); + saveAccessTokenIndex(at); + + // 返回新AccessToken + return at; + } + /** + * 构建:AccessToken Model (根据RequestAuthModel) 用于隐藏式 + * @param ra 请求授权参数Model + * @return 授权码Model + */ + public AccessTokenModel generateAccessToken(RequestAuthModel ra) { + + // 删除旧AccessToken + String oldAccessToken = getAccessTokenValue(ra.clientId, ra.loginId); + if(oldAccessToken != null) { + deleteAccessToken(oldAccessToken); + } + + // 生成新AccessToken + String atValue = randomAccessToken(ra.clientId, ra.loginId, ra.scope); + AccessTokenModel at = new AccessTokenModel(atValue, ra.clientId, ra.loginId, ra.scope); + at.openid = getOpenid(ra.clientId, ra.loginId); + at.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getAccessTokenTimeout() * 1000); + + // 保存新Token + saveAccessToken(at); + saveAccessTokenIndex(at); + + // 返回新Token + return at; + } /** - * 检查一个 Client 是否签约了指定的Scope + * 构建:ClientToken Model + * @param ra 请求授权参数Model + * @return ClientToken-Model + */ + public ClientTokenModel generateClientToken(String clientId, String scope) { + // 1、删掉 Past-Token + String ptValue = getPastTokenValue(clientId); + if(ptValue != null) { + deleteClientToken(ptValue); + } + + // 2、将Client-Token 标记 Past-Token + String ctValue = getClientTokenValue(clientId); + if(ctValue != null) { + ClientTokenModel ct = getClientToken(ctValue); + if(ct != null) { + savePastClientTokenIndex(ct); + } + } + + // 3、生成新Token + ClientTokenModel ct = new ClientTokenModel(randomClientToken(clientId, scope), clientId, scope); + ct.expiresTime = System.currentTimeMillis() + (SaOAuth2Manager.getConfig().getClientTokenTimeout() * 1000); + + // 3、保存新Token + saveClientToken(ct); + saveClientTokenIndex(ct); + + // 4、返回 + return ct; + } + + // ------------------- 其它方法 + /** + * 获取 access_token 所代表的LoginId + * @param accessToken access_token + * @return LoginId + */ + public Object getLoginIdByAccessToken(String accessToken) { + AccessTokenModel tokenModel = SaOAuth2Util.getAccessToken(accessToken); + if(tokenModel == null) { + throw new SaTokenException("无效access_token"); + } + return getLoginId(tokenModel.clientId, tokenModel.openid); + } + /** + * [OK] 构建URL:下放授权码URL + * @param redirectUri 下放地址 + * @param code code参数 + * @param state state参数 + * @return 构建完毕的URL + */ + public String buildRedirectUri(String redirectUri, String code, String state) { + String url = SaFoxUtil.joinParam(redirectUri, Param.code, code); + if(SaFoxUtil.isEmpty(state) == false) { + url = SaFoxUtil.joinParam(url, Param.state, state); + } + return url; + } + /** + * [OK] 构建URL:下放Token URL + * @param redirectUri 下放地址 + * @param token token + * @param state state参数 + * @return 构建完毕的URL + */ + public String buildRedirectUri2(String redirectUri, String token, String state) { + String url = SaFoxUtil.joinSharpParam(redirectUri, Param.token, token); + if(SaFoxUtil.isEmpty(state) == false) { + url = SaFoxUtil.joinParam(url, Param.state, state); + } + return url; + } + + // ------------------- 数据校验 + /** + * [OK] 判断:该Client是否签约了指定的Scope * @param clientId 应用id * @param scope 权限 */ - public void checkContract(String clientId, String scope) { + public boolean isContract(String clientId, String scope) { + if(SaFoxUtil.isEmpty(scope)) { + return true; + } List clientScopeList = getClientScopeList(clientId); List scopelist = Arrays.asList(scope.split(",")); - if(clientScopeList.containsAll(scopelist) == false) { - throw new SaTokenException("请求授权范围超出或无效"); - } + return clientScopeList.containsAll(scopelist); } - /** - * 指定 loginId 是否对一个 Client 授权给了指定 Scope + * [OK] 指定 loginId 是否对一个 Client 授权给了指定 Scope * @param loginId 账号id * @param clientId 应用id * @param scope 权限 @@ -117,75 +383,77 @@ public class SaOAuth2Template { public boolean isGrant(Object loginId, String clientId, String scope) { List grantScopeList = getGrantScopeList(loginId, clientId); List scopeList = convertStringToList(scope); - return grantScopeList.containsAll(scopeList); + return scopeList.size() == 0 || grantScopeList.containsAll(scopeList); } - /** - * 指定Client使用指定url作为回调地址,是否合法 + * [OK] 指定Client使用指定url作为回调地址,是否合法 * @param clientId 应用id * @param url 指定url + * @return 是否合法 */ - public void checkRightUrl(String clientId, String url) { - // 首先检测url格式 + public boolean isRightUrl(String clientId, String url) { + + // 1、是否是一个有效的url if(SaFoxUtil.isUrl(url) == false) { - throw new SaTokenException("url格式错误"); + return false; } - // ---- 检测 - // 获取此应用允许的域名列表 + // 2、截取掉?后面的部分 + int qIndex = url.indexOf("?"); + if(qIndex != -1) { + url = url.substring(0, qIndex); + } + + // 3、是否在[允许地址列表]之中 String domain = getClientDomain(clientId); - // 如果是null或者空字符串, 则代表任何域名都无法通过检查 - if(domain == null || "".equals(domain)) { - throw new SaTokenException("重定向地址无效"); + if(SaFoxUtil.isEmpty(domain)) { + return false; } - // 如果是*符号,代表允许任何域名 - if(SaOAuth2Consts.UNLIMITED_DOMAIN.equals(domain)) { - return; + List authUrlList = Arrays.asList(domain.replaceAll(" ", "").split(",")); + if(SaManager.getSaTokenAction().hasElement(authUrlList, url) == false) { + return false; } - // 获取域名进行比对 - try { - String host = new URL(url).getHost(); - List domainList = convertStringToList(domain); - if(domainList.contains(host) == false) { - throw new SaTokenException("重定向地址不在列表中"); - } - } catch (MalformedURLException e) { - throw new SaTokenException("url格式错误", e); - } + // 验证通过 + return true; } - /** - * 校验code、clientId、clientSecret 三者是否正确 + * [OK 方法名改一下]校验code、clientId、clientSecret 三者是否正确 * @param code 授权码 * @param clientId 应用id * @param clientSecret 秘钥 + * @param redirectUri 秘钥 * @return CodeModel对象 */ - public CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret) { + public CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret, String redirectUri) { - // 获取授权码信息 + // 校验:Code是否存在 CodeModel codeModel = getCode(code); - - // 验证code、client_id、client_secret if(codeModel == null) { - throw new SaTokenException("无效code"); + throw new SaOAuth2Exception("无效code"); } + // 校验:ClientId是否一致 if(codeModel.getClientId().equals(clientId) == false){ - throw new SaTokenException("无效client_id"); + throw new SaOAuth2Exception("无效client_id"); } + + // 校验:Secret是否正确 String dbClientSecret = getClientSecret(clientId); - System.out.println(dbClientSecret); - System.out.println(clientSecret); if(dbClientSecret == null || dbClientSecret.equals(clientSecret) == false){ - throw new SaTokenException("无效client_secret"); + throw new SaOAuth2Exception("无效client_secret"); + } + + // 如果提供了redirectUri,则校验其是否与请求Code时提供的一致 + if(SaFoxUtil.isEmpty(redirectUri) == false) { + if(redirectUri.equals(codeModel.redirectUri) == false) { + throw new SaOAuth2Exception("无效redirect_uri"); + } } // 返回CodeMdoel return codeModel; } - /** * 校验access_token、clientId、clientSecret 三者是否正确 * @param accessToken access_token @@ -202,7 +470,7 @@ public class SaOAuth2Template { if(tokenModel == null) { throw new SaTokenException("无效access_token"); } - if(tokenModel.getClientId().equals(clientId) == false){ + if(tokenModel.clientId.equals(clientId) == false){ throw new SaTokenException("无效client_id"); } String dbClientSecret = getClientSecret(clientId); @@ -213,341 +481,332 @@ public class SaOAuth2Template { // 返回AccessTokenModel return tokenModel; } - - - // ------------------- 逻辑相关 - - // ---- 授权码 + + // ------------------- save 数据 /** - * 根据参数生成一个授权码并返回 - * @param authModel 请求授权参数Model - * @return 授权码Model + * 持久化:Code-Model + * @param c . */ - public CodeModel generateCode(RequestAuthModel authModel) { - - // 获取参数 - String clientId = authModel.getClientId(); - String scope = authModel.getScope(); - Object loginId = authModel.getLoginId(); - String redirectUri = authModel.getRedirectUri(); - String state = authModel.getState(); - - // ------ 参数校验 - // 此Client是否签约了此Scope - checkContract(clientId, scope); - - // 校验重定向域名的格式是否合法 - checkRightUrl(clientId, redirectUri); - - // ------ 开始生成code码 - String code = createCode(clientId, scope, loginId); - CodeModel codeModel = new CodeModel(code, clientId, scope, loginId); - - // 拼接授权后重定向的域名 (拼接code和state参数) - String url = splicingParame(redirectUri, "code=" + code); - if(state != null) { - url = splicingParame(url, "state=" + state); - } - codeModel.setRedirectUri(url); - - // 拒绝授权时重定向的地址 - codeModel.setRejectUri(splicingParame(redirectUri, "handle=reject")); - - // 计算此Scope是否已经授权过了 - codeModel.setIsConfirm(isGrant(loginId, clientId, scope)); - - // ------ 开始保存 - - // 将此授权码保存到DB - long codeTimeout = SaOAuth2Manager.getConfig().getCodeTimeout(); - SaManager.getSaTokenDao().setObject(getKeyCodeModel(code), codeModel, codeTimeout); - - // 如果此[Client&账号]已经有code正在存储,则先删除它 - String key = getKeyClientLoginId(loginId, clientId); - SaManager.getSaTokenDao().delete(key); - - // 将此[Client&账号]的最新授权码保存到DB中 - // 以便于完成授权码覆盖操作: 保证每次只有最新的授权码有效 - SaManager.getSaTokenDao().set(key, code, codeTimeout); - - // 返回 - return codeModel; + public void saveCode(CodeModel c) { + SaManager.getSaTokenDao().setObject(splicingKeySaveCode(c.code), c, SaOAuth2Manager.getConfig().getCodeTimeout()); + } + /** + * 持久化:Code-索引 + * @param c . + */ + public void saveCodeIndex(CodeModel c) { + SaManager.getSaTokenDao().set(splicingKeyCodeIndex(c.clientId, c.loginId), c.code, SaOAuth2Manager.getConfig().getCodeTimeout()); + } + /** + * 持久化:AccessToken-Model + * @param at . + */ + public void saveAccessToken(AccessTokenModel at) { + SaManager.getSaTokenDao().setObject(splicingKeySaveAccessToken(at.accessToken), at, at.getExpiresIn()); + } + /** + * 持久化:AccessToken-索引 + * @param at . + */ + public void saveAccessTokenIndex(AccessTokenModel at) { + SaManager.getSaTokenDao().set(splicingKeyAccessTokenIndex(at.clientId, at.loginId), at.accessToken, at.getExpiresIn()); + } + /** + * 持久化:RefreshToken-Model + * @param rt . + */ + public void saveRefreshToken(RefreshTokenModel rt) { + SaManager.getSaTokenDao().setObject(splicingKeySaveRefreshToken(rt.refreshToken), rt, rt.getExpiresIn()); + } + /** + * 持久化:RefreshToken-索引 + * @param rt . + */ + public void saveRefreshTokenIndex(RefreshTokenModel rt) { + SaManager.getSaTokenDao().set(splicingKeyRefreshTokenIndex(rt.clientId, rt.loginId), rt.refreshToken, rt.getExpiresIn()); + } + /** + * 持久化:ClientToken-Model + * @param at . + */ + public void saveClientToken(ClientTokenModel ct) { + SaManager.getSaTokenDao().setObject(splicingKeySaveClientToken(ct.clientToken), ct, ct.getExpiresIn()); + } + /** + * 持久化:ClientToken-索引 + * @param at . + */ + public void saveClientTokenIndex(ClientTokenModel ct) { + SaManager.getSaTokenDao().set(splicingKeyClientTokenIndex(ct.clientId), ct.clientToken, ct.getExpiresIn()); + } + /** + * 持久化:Past-ClientToken-索引 + * @param at . + */ + public void savePastClientTokenIndex(ClientTokenModel ct) { + SaManager.getSaTokenDao().set(splicingKeyPastTokenIndex(ct.clientId), ct.clientToken, ct.getExpiresIn()); } + // ------------------- get 数据 [OK] /** - * 根据授权码获得授权码Model - * @param code 授权码 - * @return 授权码Model + * 获取:授权码 + * @param code . + * @return . */ public CodeModel getCode(String code) { - return (CodeModel)SaManager.getSaTokenDao().getObject(getKeyCodeModel(code)); + return (CodeModel)SaManager.getSaTokenDao().getObject(splicingKeySaveCode(code)); } - /** - * 手动更改授权码对象信息 - * @param code 授权码 - * @param codeModel 授权码Model + * 获取:授权码-Value + * @param clientId 应用id + * @param loginId 账号id + * @return . */ - public void updateCode(String code, CodeModel codeModel) { - SaManager.getSaTokenDao().updateObject(getKeyCodeModel(code), codeModel); + public String getCodeValue(String clientId, Object loginId) { + return SaManager.getSaTokenDao().get(splicingKeyCodeIndex(clientId, loginId)); } - /** - * 确认授权一个code - * @param code 授权码 + * 获取:AccessToken + * @param accessToken . + * @return . */ - public void confirmCode(String code) { - // 获取codeModel - CodeModel codeModel = getCode(code); - // 如果该code码已经确认 - if(codeModel.getIsConfirm() == true) { - return; - } - // 进行确认 - codeModel.setIsConfirm(true); - updateCode(code, codeModel); + public AccessTokenModel getAccessToken(String accessToken) { + return (AccessTokenModel)SaManager.getSaTokenDao().getObject(splicingKeySaveAccessToken(accessToken)); } - /** - * 删除一个授权码 + * 获取:AccessToken-Value + * @param clientId 应用id + * @param loginId 账号id + * @return . + */ + public String getAccessTokenValue(String clientId, Object loginId) { + return SaManager.getSaTokenDao().get(splicingKeyAccessTokenIndex(clientId, loginId)); + } + /** + * 获取:RefreshToken + * @param refreshToken . + * @return . + */ + public RefreshTokenModel getRefreshToken(String refreshToken) { + return (RefreshTokenModel)SaManager.getSaTokenDao().getObject(splicingKeySaveRefreshToken(refreshToken)); + } + /** + * 获取:RefreshToken-Value + * @param clientId 应用id + * @param loginId 账号id + * @return . + */ + public String getRefreshTokenValue(String clientId, Object loginId) { + return SaManager.getSaTokenDao().get(splicingKeyRefreshTokenIndex(clientId, loginId)); + } + + /** + * 获取:ClientTokenModel + * @param clientToken . + * @return . + */ + public ClientTokenModel getClientToken(String clientToken) { + return (ClientTokenModel)SaManager.getSaTokenDao().getObject(splicingKeySaveClientToken(clientToken)); + } + /** + * 获取:ClientTokenModel-Value + * @param clientId 应用id + * @param loginId 账号id + * @return . + */ + public String getClientTokenValue(String clientId) { + return SaManager.getSaTokenDao().get(splicingKeyClientTokenIndex(clientId)); + } + /** + * 获取:ClientTokenModel-Value + * @param clientId 应用id + * @param loginId 账号id + * @return . + */ + public String getPastTokenValue(String clientId) { + return SaManager.getSaTokenDao().get(splicingKeyPastTokenIndex(clientId)); + } + + + // ------------------- delete 数据 [OK] + /** + * 删除:授权码 * @param code 授权码 */ public void deleteCode(String code) { - SaManager.getSaTokenDao().deleteObject(getKeyCodeModel(code)); + SaManager.getSaTokenDao().deleteObject(splicingKeySaveCode(code)); } - - - // ------------------- access_token 和 refresh_token 相关 - /** - * 根据授权码Model生成一个access_token - * @param codeModel 授权码Model - * @return AccessTokenModel + * 删除:授权码索引 + * @param clientId 应用id + * @param loginId 账号id */ - public AccessTokenModel generateAccessToken(CodeModel codeModel) { - - // 先校验 - if(codeModel == null) { - throw new SaTokenException("无效code"); - } - if(codeModel.getIsConfirm() == false) { - throw new SaTokenException("该code尚未授权"); - } - - // 获取 TokenModel 并保存 - AccessTokenModel tokenModel = converCodeToAccessToken(codeModel); - SaManager.getSaTokenDao().setObject(getKeyAccessToken(tokenModel.getAccessToken()), tokenModel, SaOAuth2Manager.getConfig().getAccessTokenTimeout()); - - // 将此 CodeModel 当做 refresh_token 保存下来 - SaManager.getSaTokenDao().setObject(getKeyRefreshToken(tokenModel.getRefreshToken()), codeModel, SaOAuth2Manager.getConfig().getRefreshTokenTimeout()); - - // 返回 - return tokenModel; + public void deleteCodeIndex(String clientId, Object loginId) { + SaManager.getSaTokenDao().delete(splicingKeyCodeIndex(clientId, loginId)); } - /** - * 根据 access_token 获得其Model详细信息 - * @param accessToken access_token - * @return AccessTokenModel (授权码Model) + * 删除:AccessToken + * @param accessToken . */ - public AccessTokenModel getAccessToken(String accessToken) { - return (AccessTokenModel)SaManager.getSaTokenDao().getObject(getKeyAccessToken(accessToken)); + public void deleteAccessToken(String accessToken) { + SaManager.getSaTokenDao().deleteObject(splicingKeySaveAccessToken(accessToken)); } - /** - * 根据 refresh_token 生成一个新的 access_token - * @param refreshToken refresh_token - * @return 新的 access_token + * 删除:AccessToken索引 + * @param clientId 应用id + * @param loginId 账号id */ - public AccessTokenModel refreshAccessToken(String refreshToken) { - // 获取Model信息 - CodeModel codeModel = getRefreshToken(refreshToken); - if(codeModel == null) { - throw new SaTokenException("无效refresh_token"); - } - // 获取新的 AccessToken 并保存 - AccessTokenModel tokenModel = converCodeToAccessToken(codeModel); - tokenModel.setRefreshToken(refreshToken); - SaManager.getSaTokenDao().setObject(getKeyAccessToken(tokenModel.getAccessToken()), tokenModel, SaOAuth2Manager.getConfig().getAccessTokenTimeout()); - - // 返回 - return tokenModel; + public void deleteAccessTokenIndex(String clientId, Object loginId) { + SaManager.getSaTokenDao().delete(splicingKeyAccessTokenIndex(clientId, loginId)); } - /** - * 根据 refresh_token 获得其Model详细信息 (授权码Model) - * @param refreshToken refresh_token - * @return RefreshToken (授权码Model) + * 删除:RefreshAccess + * @param refreshAccess . */ - public CodeModel getRefreshToken(String refreshToken) { - return (CodeModel)SaManager.getSaTokenDao().getObject(getKeyRefreshToken(refreshToken)); + public void deleteRefreshAccess(String refreshAccess) { + SaManager.getSaTokenDao().deleteObject(splicingKeySaveRefreshToken(refreshAccess)); } - /** - * 获取 access_token 的有效期 - * @param accessToken access_token - * @return 有效期 + * 删除:RefreshAccess索引 + * @param clientId 应用id + * @param loginId 账号id */ - public long getAccessTokenExpiresIn(String accessToken) { - return SaManager.getSaTokenDao().getObjectTimeout(getKeyAccessToken(accessToken)); + public void deleteRefreshAccessIndex(String clientId, Object loginId) { + SaManager.getSaTokenDao().delete(splicingKeyRefreshTokenIndex(clientId, loginId)); } - /** - * 获取 refresh_token 的有效期 - * @param refreshToken refresh_token - * @return 有效期 + * 删除:ClientToken + * @param clientToken . */ - public long getRefreshTokenExpiresIn(String refreshToken) { - return SaManager.getSaTokenDao().getObjectTimeout(getKeyRefreshToken(refreshToken)); + public void deleteClientToken(String clientToken) { + SaManager.getSaTokenDao().deleteObject(splicingKeySaveClientToken(clientToken)); } - /** - * 获取 access_token 所代表的LoginId - * @param accessToken access_token - * @return LoginId + * 删除:ClientToken索引 + * @param clientId 应用id */ - public Object getLoginIdByAccessToken(String accessToken) { - AccessTokenModel tokenModel = SaOAuth2Util.getAccessToken(accessToken); - if(tokenModel == null) { - throw new SaTokenException("无效access_token"); - } - return getLoginId(tokenModel.getClientId(), tokenModel.getOpenid()); + public void deleteClientTokenIndex(String clientId) { + SaManager.getSaTokenDao().delete(splicingKeyClientTokenIndex(clientId)); + } + /** + * 删除:Past-Token索引 + * @param clientId 应用id + */ + public void deletePastTokenIndex(String clientId) { + SaManager.getSaTokenDao().delete(splicingKeyPastTokenIndex(clientId)); } - // ------------------- 自定义策略相关 - - /** - * 将指定字符串按照逗号分隔符转化为字符串集合 - * @param str 字符串 - * @return 分割后的字符串集合 - */ - public List convertStringToList(String str) { - return Arrays.asList(str.split(",")); - } - + // ------------------- Random数据 [OK] /** * 生成授权码 * @param clientId 应用id - * @param scope 权限 * @param loginId 账号id + * @param scope 权限 * @return 授权码 */ - public String createCode(String clientId, String scope, Object loginId) { - return SaFoxUtil.getRandomString(60).toLowerCase(); + public String randomCode(String clientId, Object loginId, String scope) { + return SaFoxUtil.getRandomString(60); } - /** * 生成AccessToken * @param codeModel CodeModel对象 * @return AccessToken */ - public String createAccessToken(CodeModel codeModel) { - return SaFoxUtil.getRandomString(60).toLowerCase(); + public String randomAccessToken(String clientId, Object loginId, String scope) { + return SaFoxUtil.getRandomString(60); } - /** * 生成RefreshToken * @param codeModel CodeModel对象 * @return RefreshToken */ - public String createRefreshToken(CodeModel codeModel) { - return SaFoxUtil.getRandomString(60).toLowerCase(); + public String randomRefreshToken(String clientId, Object loginId, String scope) { + return SaFoxUtil.getRandomString(60); } - /** - * 在url上拼接上kv参数并返回 - * @param url url - * @param parameStr 参数, 例如 id=1001 - * @return 拼接后的url字符串 + * 生成ClientToken + * @return RefreshToken */ - public String splicingParame(String url, String parameStr) { - // 如果参数为空, 直接返回 - if(parameStr == null || parameStr.length() == 0) { - return url; - } - int index = url.indexOf('?'); - // ? 不存在 - if(index == -1) { - return url + '?' + parameStr; - } - // ? 是最后一位 - if(index == url.length() - 1) { - return url + parameStr; - } - // ? 是其中一位 - if(index > -1 && index < url.length() - 1) { - String separatorChar = "&"; - // 如果最后一位是 不是&, 且 arg_str 第一位不是 &, 就增送一个 & - if(url.lastIndexOf(separatorChar) != url.length() - 1 && parameStr.indexOf(separatorChar) != 0) { - return url + separatorChar + parameStr; - } else { - return url + parameStr; - } - } - // 正常情况下, 代码不可能执行到此 - return url; + public String randomClientToken(String clientId, Object loginId) { + return SaFoxUtil.getRandomString(60); } - - /** - * 将 CodeModel 转换为 AccessTokenModel - * @param codeModel CodeModel对象 - * @return AccessToken对象 - */ - public AccessTokenModel converCodeToAccessToken(CodeModel codeModel) { - if(codeModel == null) { - throw new SaTokenException("无效code"); - } - AccessTokenModel tokenModel = new AccessTokenModel(); - tokenModel.setAccessToken(createAccessToken(codeModel)); - tokenModel.setRefreshToken(createRefreshToken(codeModel)); - tokenModel.setCode(codeModel.getCode()); - tokenModel.setClientId(codeModel.getClientId()); - tokenModel.setScope(codeModel.getScope()); - tokenModel.setOpenid(getOpenid(codeModel.getClientId(), codeModel.getLoginId())); - tokenModel.setTag(codeModel.getTag()); - return tokenModel; - } - - // ------------------- 返回相应key - + // ------------------- 拼接key [OK] /** - * 获取key:授权码持久化使用的key + * 拼接key:授权码持久化 * @param code 授权码 * @return key */ - public String getKeyCodeModel(String code) { + public String splicingKeySaveCode(String code) { return SaManager.getConfig().getTokenName() + ":oauth2:code:" + code; } - /** - * 获取key:[Client and 账号]最新授权码记录, 持久化使用的key - * @param loginId 账号id + * 拼接key:授权码索引 * @param clientId 应用id + * @param loginId 账号id * @return key */ - public String getKeyClientLoginId(Object loginId, String clientId) { - return SaManager.getConfig().getTokenName() + ":oauth2:newest-code:" + clientId + ":" + loginId; + public String splicingKeyCodeIndex(String clientId, Object loginId) { + return SaManager.getConfig().getTokenName() + ":oauth2:code-index:" + clientId + ":" + loginId; } - /** - * 获取key:refreshToken持久化使用的key - * @param refreshToken refreshToken - * @return key - */ - public String getKeyRefreshToken(String refreshToken) { - return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken; - } - - /** - * 获取key:accessToken持久化使用的key + * 拼接key:Access-Token持久化 * @param accessToken accessToken * @return key */ - public String getKeyAccessToken(String accessToken) { + public String splicingKeySaveAccessToken(String accessToken) { return SaManager.getConfig().getTokenName() + ":oauth2:access-token:" + accessToken; } - + /** + * 拼接key:Access-Token索引 + * @param clientId 应用id + * @param loginId 账号id + * @return key + */ + public String splicingKeyAccessTokenIndex(String clientId, Object loginId) { + return SaManager.getConfig().getTokenName() + ":oauth2:access-token-index:" + clientId + ":" + loginId; + } + /** + * 拼接key:RefreshToken持久化 + * @param refreshToken refreshToken + * @return key + */ + public String splicingKeySaveRefreshToken(String refreshToken) { + return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token:" + refreshToken; + } + /** + * 拼接key:RefreshToken索引 + * @param clientId 应用id + * @param loginId 账号id + * @return key + */ + public String splicingKeyRefreshTokenIndex(String clientId, Object loginId) { + return SaManager.getConfig().getTokenName() + ":oauth2:refresh-token-index:" + clientId + ":" + loginId; + } + /** + * 拼接key:Client-Token持久化 + * @param clientToken accessToken + * @return key + */ + public String splicingKeySaveClientToken(String clientToken) { + return SaManager.getConfig().getTokenName() + ":oauth2:client-token:" + clientToken; + } + /** + * 拼接key:ClientToken 索引 + * @param clientToken accessToken + * @return key + */ + public String splicingKeyClientTokenIndex(String clientId) { + return SaManager.getConfig().getTokenName() + ":oauth2:client-token-indedx:" + clientId; + } + /** + * 拼接key:Past-ClientToken 索引 + * @param clientId clientId + * @return key + */ + public String splicingKeyPastTokenIndex(String clientId) { + return SaManager.getConfig().getTokenName() + ":oauth2:past-token-indedx:" + clientId; + } } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java index 5a6ad400..d604e4d2 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/logic/SaOAuth2Util.java @@ -2,8 +2,11 @@ package cn.dev33.satoken.oauth2.logic; import java.util.List; +import cn.dev33.satoken.context.model.SaRequest; 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.RefreshTokenModel; import cn.dev33.satoken.oauth2.model.RequestAuthModel; /** @@ -14,8 +17,29 @@ import cn.dev33.satoken.oauth2.model.RequestAuthModel; public class SaOAuth2Util { 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 @@ -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 clientId 应用id * @param clientSecret 秘钥 + * @param redirectUri 秘钥 * @return CodeModel对象 */ - public static CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret) { - return saOAuth2Template.checkCodeIdSecret(code, clientId, clientSecret); + public static CodeModel checkCodeIdSecret(String code, String clientId, String clientSecret, String redirectUri) { + return saOAuth2Template.checkCodeIdSecret(code, clientId, clientSecret, redirectUri); } /** @@ -86,7 +130,7 @@ public class SaOAuth2Util { // ------------------- 逻辑相关 /** - * 根据参数生成一个授权码并返回 + * [OK] 根据参数生成一个授权码并返回 * @param authModel 请求授权参数Model * @return 授权码Model */ @@ -94,6 +138,7 @@ public class SaOAuth2Util { return saOAuth2Template.generateCode(authModel); } + /** * 根据授权码获得授权码Model * @param code 授权码 @@ -103,23 +148,6 @@ public class SaOAuth2Util { 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] 删除一个授权码 * @param code 授权码 @@ -129,12 +157,12 @@ public class SaOAuth2Util { } /** - * [default] 根据授权码Model生成一个access_token + * 根据授权码Model生成一个access_token * @param codeModel 授权码Model * @return AccessTokenModel */ - public static AccessTokenModel generateAccessToken(CodeModel codeModel) { - return saOAuth2Template.generateAccessToken(codeModel); + public static AccessTokenModel generateAccessToken(String code) { + return saOAuth2Template.generateAccessToken(code); } /** @@ -156,32 +184,14 @@ public class SaOAuth2Util { } /** - * [default] 根据 refresh_token 获得其Model详细信息 (授权码Model) + * [default] 根据 refresh_token 获得其Model详细信息 * @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); } - /** - * [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 * @param accessToken access_token @@ -191,10 +201,46 @@ public class SaOAuth2Util { 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); + } } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java index 21a36fa9..211dc0d1 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/AccessTokenModel.java @@ -1,5 +1,8 @@ package cn.dev33.satoken.oauth2.model; +import java.util.LinkedHashMap; +import java.util.Map; + /** * Model: access_token * @author kong @@ -10,177 +13,100 @@ public class AccessTokenModel { /** * access_token 值 */ - private String accessToken; + public String accessToken; /** * 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 */ - private String clientId; - - /** - * 授权范围 - */ - private String scope; + public String clientId; + /** + * 账号id + */ + public Object loginId; + /** * 开放账号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() { - return accessToken; - } - - /** - * @param accessToken 要设置的 accessToken - */ - public void setAccessToken(String accessToken) { + public AccessTokenModel(String accessToken, String clientId, Object loginId, String scope) { + super(); 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; - } - - /** - * @return scope - */ - public String getScope() { - return scope; - } - - /** - * @param scope 要设置的 scope - */ - public void setScope(String scope) { + this.loginId = loginId; 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() { - return openid; + public long getExpiresIn() { + long s = (expiresTime - System.currentTimeMillis()) / 1000; + return s < 1 ? -2 : s; } /** - * @param openid 要设置的 openid + * 获取:此 Refresh-Token 的剩余有效期(秒) + * @return see note */ - public void setOpenid(String openid) { - this.openid = openid; + public long getRefreshExpiresIn() { + 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 toLineMap() { + Map map = new LinkedHashMap(); + 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; + } } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ClientTokenModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ClientTokenModel.java new file mode 100644 index 00000000..5ac2ea49 --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ClientTokenModel.java @@ -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 toLineMap() { + Map map = new LinkedHashMap(); + map.put("client_token", clientToken); + map.put("expires_in", getExpiresIn()); + map.put("client_id", clientId); + map.put("scope", scope); + return map; + } + + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java index 5600606d..998da143 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/CodeModel.java @@ -7,48 +7,31 @@ package cn.dev33.satoken.oauth2.model; */ public class CodeModel { - /** + /** * 授权码 */ - private String code; + public String code; /** * 应用id */ - private String clientId; + public String clientId; /** * 授权范围 */ - private String scope; + public String scope; /** * 对应账号id */ - private Object loginId; + public Object loginId; /** - * 用户是否已经确认了这个授权 + * 重定向的地址 */ - private Boolean isConfirm; - - /** - * 确认授权后重定向的地址 - */ - private String redirectUri; - - /** - * 拒绝授权后重定向的地址 - */ - private String rejectUri; - - - /** - * 其他自定义数据 - */ - private Object tag; + public String redirectUri; - /** * 构建一个 */ @@ -62,16 +45,15 @@ public class CodeModel { * @param scope 请求授权范围 * @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(); this.code = code; this.clientId = clientId; this.scope = scope; this.loginId = loginId; - this.isConfirm = false; + this.redirectUri = redirectUri; } - /** * @return code @@ -128,21 +110,7 @@ public class CodeModel { public void setLoginId(Object loginId) { this.loginId = loginId; } - - /** - * @return isConfirm - */ - public Boolean getIsConfirm() { - return isConfirm; - } - - /** - * @param isConfirm 要设置的 isConfirm - */ - public void setIsConfirm(Boolean isConfirm) { - this.isConfirm = isConfirm; - } - + /** * @return redirectUri */ @@ -156,36 +124,11 @@ public class CodeModel { public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; } - - /** - * @return rejectUri - */ - public String getRejectUri() { - return rejectUri; + + @Override + public String toString() { + return "CodeModel [code=" + code + ", clientId=" + clientId + ", scope=" + scope + ", loginId=" + loginId + + ", redirectUri=" + redirectUri + "]"; } - /** - * @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; - } - - - - } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RefreshTokenModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RefreshTokenModel.java new file mode 100644 index 00000000..2b945a3c --- /dev/null +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RefreshTokenModel.java @@ -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; + } + +} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java index 63bbbec7..61c1ce9d 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/RequestAuthModel.java @@ -13,32 +13,32 @@ public class RequestAuthModel { /** * 应用id */ - private String clientId; + public String clientId; /** * 授权范围 */ - private String scope; + public String scope; /** * 对应的账号id */ - private Object loginId; + public Object loginId; /** * 待重定向URL */ - private String redirectUri; + public String redirectUri; /** * 授权类型, 非必填 */ - private String responseType; + public String responseType; /** * 状态标识, 可为null */ - private String state; + public String state; /** @@ -156,5 +156,6 @@ public class RequestAuthModel { } return this; } + } diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ScopeModel.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ScopeModel.java index 1f63cec2..f471d868 100644 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ScopeModel.java +++ b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/model/ScopeModel.java @@ -1,73 +1,73 @@ -package cn.dev33.satoken.oauth2.model; - -/** - * 权限Model - * @author kong - * - */ -public class ScopeModel { - - /** - * 权限名称 - */ - private String name; - - /** - * 详细介绍 - */ - private String introduce; - - - /** - * 构造一个 - */ - public ScopeModel() { - super(); - } - /** - * 构造一个 - * @param name 权限名称 - * @param introduce 权限详细介绍 - */ - public ScopeModel(String name, String introduce) { - super(); - this.name = name; - this.introduce = introduce; - } - - /** - * @return name - */ - public String getName() { - return name; - } - - /** - * @param name 要设置的 name - */ - public void setName(String name) { - this.name = name; - } - - /** - * @return introduce - */ - public String getIntroduce() { - return introduce; - } - - /** - * @param introduce 要设置的 introduce - */ - public void setIntroduce(String introduce) { - this.introduce = introduce; - } - - - - - - - - -} +//package cn.dev33.satoken.oauth2.model; +// +///** +// * 权限Model +// * @author kong +// * +// */ +//public class ScopeModel { +// +// /** +// * 权限名称 +// */ +// private String name; +// +// /** +// * 详细介绍 +// */ +// private String introduce; +// +// +// /** +// * 构造一个 +// */ +// public ScopeModel() { +// super(); +// } +// /** +// * 构造一个 +// * @param name 权限名称 +// * @param introduce 权限详细介绍 +// */ +// public ScopeModel(String name, String introduce) { +// super(); +// this.name = name; +// this.introduce = introduce; +// } +// +// /** +// * @return name +// */ +// public String getName() { +// return name; +// } +// +// /** +// * @param name 要设置的 name +// */ +// public void setName(String name) { +// this.name = name; +// } +// +// /** +// * @return introduce +// */ +// public String getIntroduce() { +// return introduce; +// } +// +// /** +// * @param introduce 要设置的 introduce +// */ +// public void setIntroduce(String introduce) { +// this.introduce = introduce; +// } +// +// +// +// +// +// +// +// +//} diff --git a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/util/SaOAuth2Consts.java b/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/util/SaOAuth2Consts.java deleted file mode 100644 index adfee815..00000000 --- a/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/util/SaOAuth2Consts.java +++ /dev/null @@ -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 = "*"; - -} diff --git a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java index ae54e932..be3dd606 100644 --- a/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java +++ b/sa-token-starter/sa-token-reactor-spring-boot-starter/src/main/java/cn/dev33/satoken/reactor/model/SaRequestForReactor.java @@ -38,7 +38,7 @@ public class SaRequestForReactor implements SaRequest { * 在 [请求体] 里获取一个值 */ @Override - public String getParameter(String name) { + public String getParam(String name) { return request.getQueryParams().getFirst(name); } diff --git a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java index c0a28b9d..191a27ad 100644 --- a/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java +++ b/sa-token-starter/sa-token-servlet/src/main/java/cn/dev33/satoken/servlet/model/SaRequestForServlet.java @@ -37,7 +37,7 @@ public class SaRequestForServlet implements SaRequest { * 在 [请求体] 里获取一个值 */ @Override - public String getParameter(String name) { + public String getParam(String name) { return request.getParameter(name); } diff --git a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java index 4a32c964..eef1ad7b 100644 --- a/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java +++ b/sa-token-starter/sa-token-solon-plugin/src/main/java/cn/dev33/satoken/solon/model/SaRequestForSolon.java @@ -21,7 +21,7 @@ public class SaRequestForSolon implements SaRequest { } @Override - public String getParameter(String s) { + public String getParam(String s) { return ctx.param(s); }