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

国外建站系统番禺有经验的网站建设

国外建站系统,番禺有经验的网站建设,定制旅游网站建设方案,网站策划是干嘛的一、介绍 token鉴权最佳的实践场景就是在单点登录系统上。 在企业发展初期#xff0c;使用的后台管理系统还比较少#xff0c;一个或者两个。 以电商系统为例#xff0c;在起步阶段#xff0c;可能只有一个商城下单系统和一个后端管理产品和库存的系统。 随着业务量越来…一、介绍 token鉴权最佳的实践场景就是在单点登录系统上。 在企业发展初期使用的后台管理系统还比较少一个或者两个。 以电商系统为例在起步阶段可能只有一个商城下单系统和一个后端管理产品和库存的系统。 随着业务量越来越大此时的业务系统会越来越复杂项目会划分成多个组每个组负责各自的领域例如A组负责商城系统的开发B组负责支付系统的开发C组负责库存系统的开发D组负责物流跟踪系统的开发E组负责每日业绩报表统计的开发...等等。 规模变大的同时人员也会逐渐的增多以研发部来说大致的人员就有这么几大类研发人员、测试人员、运维人员、产品经理、技术支持等等。 他们会频繁的登录各自的后端业务系统然后进行办公。 此时可以设想一下如果每个组都自己开发一套后端管理系统的登录假如有10个这样的系统同时一个新入职的同事需要每个系统都给他开放一个权限那么可能需要给他开通10个账号。 随着业务规模的扩大大点的公司可能高达一百多个业务系统那岂不是要配置一百多个账号让人去做这种操作岂不伤天害理。 面对这种繁琐而且又无效的工作IT大佬们想到一个办法那就是开发一套登录系统所有的业务系统都认可这套登录系统那么就可以实现只需要登录一次就可以访问其他相互信任的应用系统。 这个登录系统把它称为单点登录系统。 好了言归正传下面从两个方面来介绍单点登录系统的实现。 方案设计项目实践 二、方案设计 2.1、单体后端系统登录 在传统的单体后端系统中简单点的操作一般都会这么玩用户使用账号、密码登录之后服务器会给当前用户创建一个session会话同时也会生成一个cookie最后返回给前端。 当用户访问其他后端的服务时只需要检查一下当前用户的session是否有效如果无效就再次跳转到登录页面如果有效就进入业务处理流程。 但是如果访问不同的域名系统时这个cookie是无效的因此不能跨系统访问同时也不支持集群环境的共享。 对于单点登录的场景需要重新设计一套新的方案。 2.2、单点登录系统登录 先来一张图 这个流程图就是单点登录系统与应用系统之间的交互图。 当用户登录某应用系统时应用系统会把将客户端传入的token调用单点登录系统验证token合法性接口如果不合法就会跳转到单点登录系统的登录页面如果合法就直接进入首页。 进入登录页面之后会让用户输入用户名、密码进行登录验证如果验证成功之后会返回一个有效的token然后客户端会根据服务端返回的参数链接跳转回之前要访问的应用系统。 接着应用系统会再次验证token的合法性如果合法就进入首页流程结束。 引入单点登录系统后接入的应用系统不需要关系用户登录这块只需要对客户端的token做一下合法性鉴权操作就可以了。 而单点登录系统只需要做好用户的登录流程和鉴权并返回安全的token给客户端。 有的项目会将生成的token存放在客户端的cookie中这样做的目的就是避免每次调用接口的时候都在url里面带上token。 但是浏览器只允许同域名下的cookies可以共享对于不同的域名系统 cookie 是无法共享的。 对于这种情况可以先将 token 放入到url链接中类似上面流程图中跳转思路对于同一个应用系统可以将token放入到 cookie 中不同的应用系统可以通过 url 链接进行传递实现token的传输。 三、项目实践 在实践上token的存储有两种方案 存放在服务器如果是分布式环境一般都会存储在 redis 中存储在客户端服务器做验证天然支持分布式 3.1、存放在redis 存放在redis中是一种比较常见的处理办法最开始的时候也是这种处理办法。 当用户登录成功之后会将用户的信息作为value用uuid作为key存储到redis中各个服务集群共享用户信息。 代码实践也非常简单。 用户登录之后将用户信息存在到redis同时返回一个有效的token给客户端。 RequestMapping(value /login, method RequestMethod.POST, produces {application/json;charsetUTF-8}) public TokenVO login(RequestBody LoginDTO loginDTO){//...参数合法性验证//从数据库获取用户信息User dbUser userService.selectByUserNo(loginDTO.getUserNo);//....用户、密码验证//创建tokenString token UUID.randomUUID();//将token和用户信息存储到redis,并设置有效期2个小时redisUtil.save(token, dbUser, 2*60*60);//定义返回结果TokenVO result new TokenVO();//封装tokenresult.setToken(token);//封装应用系统访问地址result.setRedirectURL(loginDTO.getRedirectURL());return result; } 客户端收到登录成功之后根据参数组合进行跳转到对应的应用系统。 跳转示例如下http://xxx.com/page.html?tokenxxxxxx 各个应用系统只需要编写一个过滤器TokenFilter对token参数进行验证拦截即可实现对接代码如下 Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException, SecurityException {HttpServletRequest request (HttpServletRequest) servletRequest;HttpServletResponse response (HttpServletResponse) servletResponse;String requestUri request.getRequestURI();String contextPath request.getContextPath();String serviceName request.getServerName();//添加到白名单的URL放行String[] excludeUrls {(?:/images/|/css/|/js/|/template/|/static/|/web/|/constant/).$,/user/login,/user/createImage};for (String url : excludeUrls) {if (requestUri.matches(contextPath url) || (serviceName.matches(url))) {filterChain.doFilter(request, response);return;}}//运行跨域探测if(RequestMethod.OPTIONS.name().equals(request.getMethod())){filterChain.doFilter(request, response);return;}//检查token是否有效final String token request.getHeader(token);if(StringUtils.isEmpty(token) || !redisUtil.exist(token)){ResultMsgObject resultMsg new ResultMsg(4000, token已失效);//封装跳转地址resultMsg.setRedirectURL(http://sso.xxx.com?redirectURL request.getRequestURL());WebUtil.buildPrintWriter(response, resultMsg);return;}//将用户信息存入request中方便后续获取User user redisUtil.get(token);request.setAttribute(user, user);filterChain.doFilter(request, response);return; } 上面返回的是json数据给前端当然还可以直接在服务器采用重定向进行跳转具体根据自己的情况进行选择。 由于每个应用系统都可能需要进行对接因此可以将上面的方法封装成一个公共jar包应用系统只需要依赖包即可完成对接 3.2、token存放客户端 还有一种方案是将token存放客户端这种方案就是服务端根据规则对数据进行加密生成一个签名串这个签名串就是所说的token最后返回给前端。 因为加密的操作都是在服务端完成的因此密钥的管理非常重要不能泄露出去不然很容易被黑客解密出来。 最典型的应用就是JWT JWT 是由三段信息构成的将这三段信息文本用.链接一起就构成了JWT字符串。就像这样: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 如何实现呢首先需要添加一个jwt依赖包。 !-- jwt支持 -- dependencygroupIdcom.auth0/groupIdartifactIdjava-jwt/artifactIdversion3.4.0/version /dependency 然后创建一个用户信息类将会通过加密存放在token中 Data EqualsAndHashCode(callSuper false) Accessors(chain true) public class UserToken implements Serializable {private static final long serialVersionUID 1L;/*** 用户ID*/private String userId;/*** 用户登录账户*/private String userNo;/*** 用户中文名*/private String userName; } 接着创建一个JwtTokenUtil工具类用于创建token、验证token public class JwtTokenUtil {//定义token返回头部public static final String AUTH_HEADER_KEY Authorization;//token前缀public static final String TOKEN_PREFIX Bearer ;//签名密钥public static final String KEY q3t6w9z$CF)JNcQfTjWnZr4u7x;//有效期默认为 2hourpublic static final Long EXPIRATION_TIME 1000L*60*60*2;/*** 创建TOKEN* param content* return*/public static String createToken(String content){return TOKEN_PREFIX JWT.create().withSubject(content).withExpiresAt(new Date(System.currentTimeMillis() EXPIRATION_TIME)).sign(Algorithm.HMAC512(KEY));}/*** 验证token* param token*/public static String verifyToken(String token) throws Exception {try {return JWT.require(Algorithm.HMAC512(KEY)).build().verify(token.replace(TOKEN_PREFIX, )).getSubject();} catch (TokenExpiredException e){throw new Exception(token已失效请重新登录,e);} catch (JWTVerificationException e) {throw new Exception(token验证失败,e);}} } 同时编写配置类允许跨域并且创建一个权限拦截器 Slf4j Configuration public class GlobalWebMvcConfig implements WebMvcConfigurer {/*** 重写父类提供的跨域请求处理的接口* param registry*/Overridepublic void addCorsMappings(CorsRegistry registry) {// 添加映射路径registry.addMapping(/**)// 放行哪些原始域.allowedOrigins(*)// 是否发送Cookie信息.allowCredentials(true)// 放行哪些原始域(请求方式).allowedMethods(GET, POST, DELETE, PUT, OPTIONS, HEAD)// 放行哪些原始域(头部信息).allowedHeaders(*)// 暴露哪些头部信息因为跨域访问默认不能获取全部头部信息.exposedHeaders(Server,Content-Length, Authorization, Access-Token, Access-Control-Allow-Origin,Access-Control-Allow-Credentials);}/*** 添加拦截器* param registry*/Overridepublic void addInterceptors(InterceptorRegistry registry) {//添加权限拦截器registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns(/**).excludePathPatterns(/static/**);} } 使用AuthenticationInterceptor拦截器对接口参数进行验证 Slf4j public class AuthenticationInterceptor implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 从http请求头中取出tokenfinal String token request.getHeader(JwtTokenUtil.AUTH_HEADER_KEY);//如果不是映射到方法直接通过if(!(handler instanceof HandlerMethod)){return true;}//如果是方法探测直接通过if (HttpMethod.OPTIONS.equals(request.getMethod())) {response.setStatus(HttpServletResponse.SC_OK);return true;}//如果方法有JwtIgnore注解直接通过HandlerMethod handlerMethod (HandlerMethod) handler;Method methodhandlerMethod.getMethod();if (method.isAnnotationPresent(JwtIgnore.class)) {JwtIgnore jwtIgnore method.getAnnotation(JwtIgnore.class);if(jwtIgnore.value()){return true;}}LocalAssert.isStringEmpty(token, token为空鉴权失败);//验证并获取token内部信息String userToken JwtTokenUtil.verifyToken(token);//将token放入本地缓存WebContextUtil.setUserToken(userToken);return true;}Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//方法结束后移除缓存的tokenWebContextUtil.removeUserToken();} } 最后在controller层用户登录之后创建一个token存放在头部即可 /*** 登录* param userDto* return*/ JwtIgnore RequestMapping(value /login, method RequestMethod.POST, produces {application/json;charsetUTF-8}) public UserVo login(RequestBody UserDto userDto, HttpServletResponse response){//...参数合法性验证//从数据库获取用户信息User dbUser userService.selectByUserNo(userDto.getUserNo);//....用户、密码验证//创建token并将token放在响应头UserToken userToken new UserToken();BeanUtils.copyProperties(dbUser,userToken);String token JwtTokenUtil.createToken(JSONObject.toJSONString(userToken));response.setHeader(JwtTokenUtil.AUTH_HEADER_KEY, token);//定义返回结果UserVo result new UserVo();BeanUtils.copyProperties(dbUser,result);return result; } 到这里基本就完成了 其中AuthenticationInterceptor中用到的JwtIgnore是一个注解用于不需要验证token的方法上例如验证码的获取等等。 Target({ElementType.METHOD, ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) public interface JwtIgnore {boolean value() default true; } 而WebContextUtil是一个线程缓存工具类其他接口通过这个方法即可从token中获取用户信息。 public class WebContextUtil {//本地线程缓存tokenprivate static ThreadLocalString local new ThreadLocal();/*** 设置token信息* param content*/public static void setUserToken(String content){removeUserToken();local.set(content);}/*** 获取token信息* return*/public static UserToken getUserToken(){if(local.get() ! null){UserToken userToken JSONObject.parseObject(local.get() , UserToken.class);return userToken;}return null;}/*** 移除token信息* return*/public static void removeUserToken(){if(local.get() ! null){local.remove();}} } 对应用系统而言重点在于token的验证可以将拦截器方法封装成一个公共的jar包然后各个应用系统引用即可 和上面介绍的token存储到redis方案类似不同点在于一个将用户数据存储到redis另一个是采用加密算法存储到客户端进行传输。 四、小结 在实际的使用过程中更加倾向于采用jwt方案直接在服务端使用签名加密算法生成一个token然后在客户端进行流转天然支持分布式但是要注意加密时用的密钥要安全管理。 而采用redis方案存储的时候需要搭建高可用的集群环境同时保证缓存数据不会失效等等维护成本高 在实际的实现上每个公司玩法不一样有的安全性要求高后端还会加上密钥环节进行安全验证基本思路大同小异。
http://www.zqtcl.cn/news/104669/

相关文章:

  • 西宁网站制作公司排名网站开发开题报告范文2019
  • 公司做竞拍网站的收入怎么报税网易门户网站建设
  • 网站建设投资建设一个网站成本多少
  • 如何优化网站内部链接wordpress后台无法预览文章
  • 小白一步步做网站开题报告旅游网站建设
  • 鞋帽箱包网站建设怎么给网站做外链邵连虎
  • linux网站建设模板上海发布公众号官网
  • 信息科技有限公司网站建设网站运营主要做什么
  • 广州建筑公司网站网站上的动态图怎么做
  • win10系统可以做网站搭建网站和微信同步建设
  • 在哪里能找到做网站的人医疗网站建设意见
  • 网站制作及实现wordpress在线工具
  • 网站制作中企动力优响应式网站建设有利于seo
  • 区块链媒体网站建设wordpress页脚内容居中
  • php手机网站开发工具成都的教育品牌网站建设
  • 苏州建网站要多少钱八爪鱼采集器 wordpress
  • 确定网站风格thinkphp相比Wordpress
  • 网站全屏代码wordpress无法连接ftp
  • 做ppt配图好用的网站重庆制作网站有哪些
  • 门户网站建设进度安卓手机开发者模式
  • 招商网站建设需要什么网站开发 在线数据库
  • 创建网站代码网站二级页怎么做
  • 网站建设 前沿文章建设网站网站建设公司
  • dede网站seo微信开店怎么注册开店流程
  • 苏华建设集团有限公司网站wordpress 普通文本 quot
  • 网站首页倒计时功能怎么做学网站开发技术
  • 上海网站备案流程欧宇公司网络建设方案
  • 网站营销型办公室装修费用会计分录
  • 个人网站网页设计模板学校ftp服务器做网站
  • 黄江网站建设外贸公司用的采购储运财务软件