当前位置: 首页 > wzjs >正文

中国购物网站大全排名营销网站建设yyeygtytty

中国购物网站大全排名,营销网站建设yyeygtytty,网站规划建设书,wordpress中级课程凌风主讲文章目录 概要功能结构图11.OAuth2.0认证12.分布式会话13.参数签名 概要 Sa-Token核心功能解剖,功能列表: OAuth2.0认证 —— 轻松搭建 OAuth2.0 服务,支持openid模式 。分布式会话 —— 提供共享数据中心分布式会话方案。参数签名 —— 提…

文章目录

    • 概要
    • 功能结构图
      • 11.OAuth2.0认证
      • 12.分布式会话
      • 13.参数签名

概要

Sa-Token核心功能解剖,功能列表:

  1. OAuth2.0认证 —— 轻松搭建 OAuth2.0 服务,支持openid模式 。
  2. 分布式会话 —— 提供共享数据中心分布式会话方案。
  3. 参数签名 —— 提供跨系统API调用签名校验模块,防参数篡改,防请求重放。

功能结构图

在这里插入图片描述

11.OAuth2.0认证

轻松搭建 OAuth2.0 服务,支持openid模式 。
4. OAuth2.0 四种模式
基于不同的使用场景,OAuth2.0设计了四种模式:

  1. 授权码(Authorization Code):OAuth2.0 标准授权步骤,Server 端向 Client 端下放 Code 码,Client 端再用 Code 码换取授权 Access-Token。
  2. 隐藏式(Implicit):无法使用授权码模式时的备用选择,Server 端使用 URL 重定向方式直接将 Access-Token 下放到 Client 端页面。
  3. 密码式(Password):Client 端直接拿着用户的账号密码换取授权 Access-Token。
  4. 客户端凭证(Client Credentials):Server 端针对 Client 级别的 Token,代表应用自身的资源授权。
    在这里插入图片描述
    前提:修改hosts文件(C:\windows\system32\drivers\etc\hosts),添加以下IP映射,方便我们进行测试
127.0.0.1 sa-oauth-server.com
127.0.0.1 sa-oauth-client.com

OAuth2-Server端:sa-token-demo-oauth2-server 源码链接
OAuth2-Client端: sa-token-demo-oauth2-client 源码链接

一、Server 认证端(sa-token-demo-oauth2-server端)、认证中心
1.application.yml

server:port: 8000sa-token:token-name: satokenis-log: truejwt-secret-key: saxsaxsaxsax# OAuth2.0 配置oauth2-server:enable-authorization-code: true# 是否全局开启 Implicit 模式enable-implicit: true# 是否全局开启密码模式enable-password: true# 是否全局开启客户端模式enable-client-credentials: true# 定义哪些 scope 是高级权限,多个用逗号隔开# higher-scope: openid,userid# 定义哪些 scope 是低级权限,多个用逗号隔开# lower-scope: userinfo
spring:#根据部署调整redis:ip: 127.0.0.1port: 6379password: ''database: 1

2、启动日志

2025-03-31 15:49:01.001  INFO 20716 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8000 (http)Sa-Token-OAuth2 Server端启动成功,配置如下:
SaOAuth2ServerConfig{enableAuthorizationCode=true, enableImplicit=true, enablePassword=true, enableClientCredentials=true, isNewRefresh=false, codeTimeout=300, accessTokenTimeout=7200, refreshTokenTimeout=2592000, clientTokenTimeout=7200, lowerClientTokenTimeout=-1, openidDigestPrefix='openid_default_digest_prefix, unionidDigestPrefix='unionid_default_digest_prefix, higherScope='null, lowerScope='null, mode4ReturnAccessToken='false, hideStatusField='false, oidc='SaOAuth2OidcConfig{iss='null', idTokenTimeout=600}}
  1. 统一认证登录(接收:客户端访问登录、OAuth模式访问 等请求)
    I) 登录认证请求:
  • http://sa-oauth-server.com:8000/oauth2/doLogin?name=sa&pwd=123456

SaOAuth2ServerController: Sa-Token-OAuth2 Server 认证端 Controller

@RestController
public class SaOAuth2ServerController {// OAuth2-Server 端:处理所有 OAuth2 相关请求@RequestMapping("/oauth2/*")public Object request() {System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());return SaOAuth2ServerProcessor.instance.dister();}............}
}
  1. Sa-Token OAuth2 请求处理器:处理 Server 端请求, 路由分发
public class SaOAuth2ServerProcessor {public static SaOAuth2ServerProcessor instance = new SaOAuth2ServerProcessor();/*** 处理 Server 端请求, 路由分发* @return 处理结果*/public Object dister() {// 获取变量SaRequest req = SaHolder.getRequest();// ------------------ 路由分发 ------------------// doLogin 登录接口if(req.isPath(Api.doLogin)) {return doLogin();}}
-------------->/*** doLogin 登录接口* @return 处理结果*/public Object doLogin() {// 获取变量SaRequest req = SaHolder.getRequest();SaOAuth2ServerConfig cfg = SaOAuth2Manager.getServerConfig();return cfg.doLoginHandle.apply(req.getParam(Param.name), req.getParam(Param.pwd));}

SaOAuth2ServerController类 完成登录

@RestController
public class SaOAuth2ServerController {// Sa-Token OAuth2 定制化配置@Autowiredpublic void configOAuth2Server(SaOAuth2ServerConfig oauth2Server) {// 登录处理函数oauth2Server.doLoginHandle = (name, pwd) -> {if("sa".equals(name) && "123456".equals(pwd)) {StpUtil.login(10001);return SaResult.ok().set("satoken", StpUtil.getTokenValue());}return SaResult.error("账号名或密码错误");};
}

登录完成,callback到 客户端主页:http://sa-oauth-client.com:8002

其它 过程:
II)授权[http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/]

     public Object dister() {// 获取变量SaRequest req = SaHolder.getRequest();// ------------------ 路由分发 ------------------// 模式一:Code授权码 || 模式二:隐藏式if(req.isPath(Api.authorize)) {return authorize();}
------------>
/*** 模式一:Code授权码 / 模式二:隐藏式* @return 处理结果*/public Object authorize() {// 获取变量SaRequest req = SaHolder.getRequest();SaResponse res = SaHolder.getResponse();SaOAuth2ServerConfig cfg = SaOAuth2Manager.getServerConfig();SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();String responseType = req.getParamNotNull(Param.response_type);// 3、构建请求 ModelRequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, SaOAuth2Manager.getStpLogic().getLoginId());// 6、判断:如果此次申请的Scope,该用户尚未授权,则转到授权页面boolean isNeedCarefulConfirm = oauth2Template.isNeedCarefulConfirm(ra.loginId, ra.clientId, ra.scopes);if(isNeedCarefulConfirm) {return cfg.confirmView.apply(ra.clientId, ra.scopes);}}

第一次该用户尚未授权,则转到授权页面。

III)确认授权:用户在WEB页 同意授权 [/oauth2/doConfirm]

     public Object dister() {// 获取变量SaRequest req = SaHolder.getRequest(); // doConfirm 确认授权接口if(req.isPath(Api.doConfirm)) {return doConfirm();}
------------>/*** doConfirm 确认授权接口* @return 处理结果*/public Object doConfirm() {// 获取变量SaRequest req = SaHolder.getRequest();String clientId = req.getParamNotNull(Param.client_id);Object loginId = SaOAuth2Manager.getStpLogic().getLoginId();String scope = req.getParamNotNull(Param.scope);List<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(scope);SaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();SaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();// 确认授权oauth2Template.saveGrantScope(clientId, loginId, scopes);.......// -------- 情况2:需要返回最终的 redirect_uri 地址// s3、构建请求 ModelRequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, loginId);// 7、判断授权类型,构建不同的重定向地址// 		如果是 授权码式,则:开始重定向授权,下放codeif(ResponseType.code.equals(ra.responseType)) {CodeModel codeModel = dataGenerate.generateCode(ra);String redirectUri = dataGenerate.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);return SaResult.ok().set(Param.redirect_uri, redirectUri);}............}
------------>
/*** 持久化:用户授权记录* @param clientId 应用id* @param loginId 账号id* @param scopes 权限列表*/default void saveGrantScope(String clientId, Object loginId, List<String> scopes) {if( ! SaFoxUtil.isEmpty(scopes)) {long ttl = checkClientModel(clientId).getAccessTokenTimeout();String value = SaOAuth2Manager.getDataConverter().convertScopeListToString(scopes);getSaTokenDao().set(splicingGrantScopeKey(clientId, loginId), value, ttl);}}
------------>/*** 拼接key:用户授权记录* @param clientId 应用id* @param loginId 账号id* @return key*/default String splicingGrantScopeKey(String clientId, Object loginId) {return getSaTokenConfig().getTokenName() + ":oauth2:grant-scope:" + clientId + ":" + loginId;}` Redis 存储 用户授权 [satoken:oauth2:grant-scope:clientId:loginId, scopes集合]`------------>
/*** 构建Model:Code授权码* @param ra 请求参数Model* @return 授权码Model*/@Overridepublic CodeModel generateCode(RequestAuthModel ra) {SaOAuth2Dao dao = SaOAuth2Manager.getDao();// 删除旧Codedao.deleteCode(dao.getCodeValue(ra.clientId, ra.loginId));// 生成新CodeString codeValue = SaOAuth2Strategy.instance.createCodeValue.execute(ra.clientId, ra.loginId, ra.scopes);CodeModel cm = new CodeModel(codeValue, ra.clientId, ra.scopes, ra.loginId, ra.redirectUri, ra.getNonce());// 保存新Codedao.saveCode(cm);dao.saveCodeIndex(cm);// 保存code-noncedao.saveCodeNonceIndex(cm);// 返回return cm;}

public interface SaOAuth2Dao {//save 数据:持久化:Code-Modeldefault void saveCode(CodeModel c) {if(c == null) {return;}getSaTokenDao().setObject(splicingCodeSaveKey(c.code), c, SaOAuth2Manager.getServerConfig().getCodeTimeout());}
} 
-----------/*** 拼接key:Code持久化* @param code 授权码* @return key*/default String splicingCodeSaveKey(String code) {return getSaTokenConfig().getTokenName() + ":oauth2:code:" + code;}`存储 code 授权码 [satoken:oauth2:code:code值(60位), CodeModel对象]`

执行完成后,String redirectUri = dataGenerate.buildRedirectUri(ra.redirectUri, codeModel.code, ra.state);
重定向: http://sa-oauth-client.com:8002/code=60位串

V)Code码获取 Access-Token

	public Object dister() {...........// Code 换 Access-Token || 模式三:密码式if(req.isPath(Api.token)) {return token();}---------------public Object token() {AccessTokenModel accessTokenModel = SaOAuth2Strategy.instance.grantTypeAuth.apply(SaHolder.getRequest());return SaOAuth2Manager.getDataResolver().buildAccessTokenReturnValue(accessTokenModel);}--------------/*** 根据 scope 信息对一个 AccessTokenModel 进行加工处理*/public SaOAuth2GrantTypeAuthFunction grantTypeAuth = (req) -> {String grantType = req.getParamNotNull(SaOAuth2Consts.Param.grant_type);SaOAuth2GrantTypeHandlerInterface grantTypeHandler = grantTypeHandlerMap.get(grantType);...................// 看看全局是否开启了此 grantType........// 调用 处理器return grantTypeHandler.getAccessToken(req, clientIdAndSecretModel.getClientId(), scopes);};

authorization_code grant_type 处理器

public class AuthorizationCodeGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterface {@Overridepublic String getHandlerGrantType() {return GrantType.authorization_code;}@Overridepublic AccessTokenModel getAccessToken(SaRequest req, String clientId, List<String> scopes) {.............// 构建 Access-Token、返回AccessTokenModel accessTokenModel = SaOAuth2Manager.getDataGenerate().generateAccessToken(code);return accessTokenModel;}}

Sa-Token OAuth2 数据构建器,默认实现类SaOAuth2DataGenerateDefaultImpl :

public class SaOAuth2DataGenerateDefaultImpl implements SaOAuth2DataGenerate {............/*** 构建Model:Access-Token* @param code 授权码* @return AccessToken Model*/@Overridepublic AccessTokenModel generateAccessToken(String code) {SaOAuth2Dao dao = SaOAuth2Manager.getDao();SaOAuth2DataConverter dataConverter = SaOAuth2Manager.getDataConverter();.............// 3、生成tokenAccessTokenModel at = dataConverter.convertCodeToAccessToken(cm);SaOAuth2Strategy.instance.workAccessTokenByScope.accept(at);RefreshTokenModel rt = dataConverter.convertAccessTokenToRefreshToken(at);at.refreshToken = rt.refreshToken;at.refreshExpiresTime = rt.expiresTime;// 4、保存tokendao.saveAccessToken(at);dao.saveAccessTokenIndex(at);dao.saveRefreshToken(rt);dao.saveRefreshTokenIndex(rt);// 5、删除此Codedao.deleteCode(code);dao.deleteCodeIndex(cm.clientId, cm.loginId);// 6、返回 Access-Tokenreturn at;}

二、客户端(sa-token-demo-oauth2-client端)
1、application.yml

server:port: 8002
sa-token.token-name: satoken-client

2、启动日志

2025-03-31 15:59:54.366  INFO 21036 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8002 (http) with context 
Sa-Token-OAuth Client端启动成功
-------------------- Sa-Token-OAuth2 示例 --------------------
首先在host文件 (C:\windows\system32\drivers\etc\hosts) 添加以下内容: 127.0.0.1 sa-oauth-server.com 127.0.0.1 sa-oauth-client.com 
再从浏览器访问:http://sa-oauth-client.com:8002

3.浏览器访问:http://sa-oauth-client.com:8002
未登录 —> 先登录(被 服务端拦截,进入 服务端【4. 统一认证登录】
http://sa-oauth-server.com:8000/oauth2/doLogin?name=sa&pwd=123456
登录成功后,开始授权。

  1. 选择 模式一:授权码(Authorization Code) 方式 认证
    1. 点我开始授权登录(静默授权)----> 访问 认证中心(Server 认证端):
http://sa-oauth-server.com:8000/oauth2/authorize?response_type=code
&client_id=1001&redirect_uri=http://sa-oauth-client.com:8002/
  • response_type:code 即模式一:授权码
  • redirect_uri: 认证成功后的callback 主页(一般为子系统home主页)
    2) 认证中心【 II)确认授权】:用户 同意授权后 ,可进行Token和用户信息等获取
    3)code码获取Token和用户信息
http://sa-oauth-server.com:8000/oauth2/token?grant_type=authorization_code&client_id=1001&client_secret=aaaa-bbbb-cccc-dddd-eeee&code={code}

进入 认证中心【V)Code码获取 Access-Token】

12.分布式会话

提供共享数据中心分布式会话方案。

  • 需求场景
    微服务架构下的第一个难题便是数据同步,单机版的Session在分布式环境下一般不能正常工作,为此我们需要对框架做一些特定的处理。
    首先我们要明白,分布式环境下为什么Session会失效?因为用户在一个节点对会话做出的更改无法实时同步到其它的节点, 这就导致一个很严重的问题:如果用户在节点一上已经登录成功,那么当下一次的请求落在节点二上时,对节点二来讲,此用户仍然是未登录状态。
  • 解决方案
    要怎么解决这个问题呢?目前的主流方案有四种:
  1. Session同步:只要一个节点的数据发生了改变,就强制同步到其它所有节点
  2. Session粘滞:通过一定的算法,保证一个用户的所有请求都稳定的落在一个节点之上,对这个用户来讲,就好像还是在访问一个单机版的服务
  3. 建立会话中心:将Session存储在缓存中间件,使每个节点都变成无状态服务,例如Redis
  4. 颁发无状态token:放弃Session机制,将用户数据写入令牌,使会话数据做到令牌自解释,例如jwt
  • 方案选择
    方案一:性能消耗太大,不太考虑
    方案二:需要从网关处动手,与框架无关
    方案三:Sa-Token 整合Redis非常简单,详见章节:集成 Redis
    方案四:详见官方仓库中 Sa-Token 整合jwt的示例

13.参数签名

提供跨系统API调用签名校验模块,防参数篡改,防请求重放。

涉及跨系统接口调用时,我们容易碰到以下安全问题:
请求身份被伪造。
请求参数被篡改。
请求被抓包,然后重放攻击。

解决思路:
1.使用摘要算法和密钥(secretKey:由双方制定32位字符串)生成参数签名
2.签名算法 追加 nonce 随机字符串,存储在缓存-redis保存15分钟 (防止被抓包,多次重放攻击)
3.签名算法 追加timestamp 时间戳,将请求的有效性限定在一个有限时间范围内,例如 15分钟。

客户端请求签名,传递参数以及签名sign值过程:

// 声明变量---根据业务接口 自定义
long userId = 10001;
long money = 1000;
String nonce = SaFoxUtil.getRandomString(32); // 随机32位字符串
long timestamp = System.currentTimeMillis(); // 系统当前时间戳 
String secretKey = "xxxxxxxxxxxxxxxxxxxx";
// 计算 sign 参数
String sign = md5("money=" + money + "&userId=" + userId + "&nonce=" + nonce + "&timestamp =" + timestamp + "&key=" + secretKey);
// 将 sign 拼接在请求地址后面
String res = HttpUtil.request("http://b.com/api/addMoney?userId=" + userId + "&nonce=" + nonce + "&timestamp =" + timestamp + "&money=" + money + "&sign=" + sign);

服务验证签名:解析参数,匹配签名sign值

@RequestMapping("addMoney")
public SaResult addMoney(long userId, long money, String nonce, long timestamp, String sign) {// 1、检查timestamp是否超出允许的范围[此处需要取绝对值,防止系统A与系统B服务器时钟不一致]long timestampDisparity = Math.abs(System.currentTimeMillis() - timestamp);if(timestampDisparity > 1000 * 60 * 15) {return SaResult.error("timestamp 时间差超出允许的范围,请求无效");}// 2、检查此 nonce 是否已被使用过,防止被抓包,多次重放攻击if(CacheUtil.get("nonce_" + nonce) != null) {return SaResult.error("此 nonce 已被使用过了,请求无效");}//在 B 系统,使用同样的算法、同样的密钥,计算出 sign2,与传入的 sign 进行比对String sign2 = md5("money=" + money + "&userId=" + userId + "&nonce=" + nonce + "&timestamp =" + timestamp + "&key=" + secretKey);if( ! sign2.equals(sign)) {return SaResult.error("无效 sign,无法响应请求");}// 2、业务代码 // ...// 3、返回return SaResult.ok();
}

文章转载自:

http://5EdWk8Py.djbhz.cn
http://79sLgLDf.djbhz.cn
http://OgbJn4FS.djbhz.cn
http://4CIK3nbu.djbhz.cn
http://LbIKR0nD.djbhz.cn
http://8BCZHGRl.djbhz.cn
http://2ZMDYeFE.djbhz.cn
http://6p8iP8UE.djbhz.cn
http://rYY3c7Md.djbhz.cn
http://Pus8KJ94.djbhz.cn
http://pfvlwh49.djbhz.cn
http://5JV7Paki.djbhz.cn
http://mjWVC9Is.djbhz.cn
http://4g5PKYLP.djbhz.cn
http://aOoY52U6.djbhz.cn
http://hDYhZyPO.djbhz.cn
http://yWPRDh0B.djbhz.cn
http://KfvoLWsl.djbhz.cn
http://n1riovn9.djbhz.cn
http://xZoSFVDb.djbhz.cn
http://0E4a8wWY.djbhz.cn
http://dSAD00ER.djbhz.cn
http://yokexguB.djbhz.cn
http://lCJNBe0A.djbhz.cn
http://SS9Wrhc6.djbhz.cn
http://zhYa0PHT.djbhz.cn
http://TkBkPDoE.djbhz.cn
http://NE3U7fAD.djbhz.cn
http://0UQztyTw.djbhz.cn
http://9Q7zIysy.djbhz.cn
http://www.dtcms.com/wzjs/665224.html

相关文章:

  • 江苏手机网站建设php 网站下载器
  • 网站后台怎么控制做网站灵宝
  • 网站源码怎么用高德地图怎么申报地址
  • o2o网站建设基本流程贵阳网站商城建设
  • 东莞装饰网站建设flash网站模板免费下载
  • 烟台提供网站设计制作职高门户网站建设标准
  • 查找企业信息的网站网站建设维护费 会计科目
  • 境外企业网站推广生活中实用的产品设计
  • 网站集约化建设报告做电影网站需要多打了服务器
  • 做淘客网站要多大的服务器永久免费做网站
  • 麒麟网站建设集团网站网页模板
  • 网站后台排版布局呼和浩特市做网站公司好的
  • 佛山网站制作哪家北京中小企业建站价格
  • 哪里可以免费注册网站网站活动专题页面
  • 什么网站可以做会计题目百度竞价排名收费
  • 做网站有名的公司湖南it网站建设mxtia
  • 会展网站建设大余网站建设
  • 做普通网站价格wordpress 配置邮件
  • 网站开发专业主修课程最新网络营销方式
  • 网站规划说明书net网站建设
  • 深圳论坛网站设计哪家公司好网站专项审批查询
  • 网站制作苏州企业通过网络营销学到了什么
  • 手机网站制作哪家好国外创意设计网站
  • 济南专业的设计网站温州网站关键词
  • 手机网站转app开发教程网站制作电话多少
  • 大兴网站设计揭阳高端品牌网站建设
  • 网站怎么seo关键词排名优化推广有名的网页游戏
  • 怎么做frontpage网站网页制作素材图片是什么格式
  • 网站建设销售工作内容女主网站和男主做
  • 网站不能风格哪个微信公众号有a