SpringCloud+SpringBoot分布式电子商务源码
在分布式环境中,如何支持PC、APP(ios、android)等多端的会话共享,这也是所有公司都需要的解决方案,用传统的session方式来解决,我想已经out了,我们是否可以找一个通用的方案,比如用传统cas来实现多系统之间的sso单点登录或使用oauth的第三方登录方案? 今天给大家简单讲解一下使用spring拦截器Interceptor机制、jwt认证方式、redis分布式缓存实现sso单点登录,闲话少说,直接把步骤记录下来分享给大家:
1. 引入jwt的相关jar包,在项目pom.xml中引入:
<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>2.2.0</version> </dependency>
2. 拦截器配置:
<mvc:interceptor> <mvc:mapping path="${adminPath}/**" /> <mvc:exclude-mapping path="${adminPath}/rest/login"/> <bean class="com.ml.honghu.interceptor.LoginInterceptor" /> </mvc:interceptor>
我这里简单配置了要拦截的url和过滤的url(这个根据自己项目来定)
3. 编写jwt的加密或者解密工具类:
public class JWT { private static final String SECRET = "HONGHUJWT1234567890QWERTYUIOPASDFGHJKLZXCVBNM"; private static final String EXP = "exp"; private static final String PAYLOAD = "payload"; //加密 public static <T> String sign(T object, long maxAge) { try { final JWTSigner signer = new JWTSigner(SECRET); final Map<String, Object> claims = new HashMap<String, Object>(); ObjectMapper mapper = new ObjectMapper(); String jsonString = mapper.writeValueAsString(object); claims.put(PAYLOAD, jsonString); claims.put(EXP, System.currentTimeMillis() + maxAge); return signer.sign(claims); } catch(Exception e) { return null; } } //解密 public static<T> T unsign(String jwt, Class<T> classT) { final JWTVerifier verifier = new JWTVerifier(SECRET); try { final Map<String,Object> claims= verifier.verify(jwt); if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) { String json = (String)claims.get(PAYLOAD); ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(json, classT); } return null; } catch (Exception e) { return null; } } }
这个加密工具类是我从网上找的,如果各位要修改,可以按照自己业务修改即可。
4. 创建Login.java对象,用来进行jwt的加密或者解密:
public class Login implements Serializable{ /** * */ private static final long serialVersionUID = 1899232511233819216L; /** * 用户id */ private String uid; /** * 登录用户名 */ private String loginName; /** * 登录密码 */ private String password; public Login(){ super(); } public Login(String uid, String loginName, String password){ this.uid = uid; this.loginName = loginName; this.password = password; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
5. 定义RedisLogin对象,用来通过uid往redis进行user对象存储:
public class RedisLogin implements Serializable{ /** * */ private static final long serialVersionUID = 8116817810829835862L; /** * 用户id */ private String uid; /** * jwt生成的token信息 */ private String token; /** * 登录或刷新应用的时间 */ private long refTime; public RedisLogin(){ } public RedisLogin(String uid, String token, long refTime){ this.uid = uid; this.token = token; this.refTime = refTime; } public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public long getRefTime() { return refTime; } public void setRefTime(long refTime) { this.refTime = refTime; } }
6. 编写LoginInterceptor.java拦截器
public class LoginInterceptor implements HandlerInterceptor{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { PrintWriter writer = null; HandlerMethod method = null; try { method = (HandlerMethod) handler; } catch (Exception e) { writer = response.getWriter(); ResponseVO responseVO = ResponseCode.buildEnumResponseVO(ResponseCode.REQUEST_URL_NOT_SERVICE, false); responseMessage(response, writer, responseVO); return false; } IsLogin isLogin = method.getMethodAnnotation(IsLogin.class); if(null == isLogin){ return true; } response.setCharacterEncoding("utf-8"); String token = request.getHeader("token"); String uid = request.getHeader("uid"); //token不存在 if(StringUtils.isEmpty(token)) { writer = response.getWriter(); ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TOKEN_NOT_NULL, false); responseMessage(response, writer, responseVO); return false; } if(StringUtils.isEmpty(uid)){ writer = response.getWriter(); ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_NULL, false); responseMessage(response, writer, responseVO); return false; } Login login = JWT.unsign(token, Login.class); //解密token后的loginId与用户传来的loginId判断是否一致 if(null == login || !StringUtils.equals(login.getUid(), uid)){ writer = response.getWriter(); ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED, false); responseMessage(response, writer, responseVO); return false; } //验证登录时间 RedisLogin redisLogin = (RedisLogin)JedisUtils.getObject(uid); if(null == redisLogin){ writer = response.getWriter(); ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.RESPONSE_CODE_UNLOGIN_ERROR, false); responseMessage(response, writer, responseVO); return false; } if(!StringUtils.equals(token, redisLogin.getToken())){ writer = response.getWriter(); ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED, false); responseMessage(response, writer, responseVO); return false; } //系统时间>有效期(说明已经超过有效期) if (System.currentTimeMillis() > redisLogin.getRefTime()) { writer = response.getWriter(); ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TIME_EXP, false); responseMessage(response, writer, responseVO); return false; } //重新刷新有效期 redisLogin = new RedisLogin(uid, token, System.currentTimeMillis() + 60L* 1000L* 30L); JedisUtils.setObject(uid , redisLogin, 360000000); return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseVO responseVO) { response.setContentType("application/json; charset=utf-8"); JSONObject result = new JSONObject(); result.put("result", responseVO); out.print(result); out.flush(); out.close(); } }
7. 定义异常的LoginResponseCode
public enum LoginResponseCode { USERID_NOT_NULL(3001,"用户id不能为空."), LOGIN_TOKEN_NOT_NULL(3002,"登录token不能为空."), USERID_NOT_UNAUTHORIZED(3003, "用户token或ID验证不通过"), RESPONSE_CODE_UNLOGIN_ERROR(421, "未登录异常"), LOGIN_TIME_EXP(3004, "登录时间超长,请重新登录"); // 成员变量 private int code; //状态码 private String message; //返回消息 // 构造方法 private LoginResponseCode(int code,String message) { this.code = code; this.message = message; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public static ResponseVO buildEnumResponseVO(LoginResponseCode responseCode, Object data) { return new ResponseVO(responseCode.getCode(),responseCode.getMessage(),data); } public static Map<String, Object> buildReturnMap(LoginResponseCode responseCode, Object data) { Map<String, Object> map = new HashMap<String, Object>(); map.put("code", responseCode.getCode()); map.put("message", responseCode.getMessage()); map.put("data", data); return map; } }
8. 编写统一sso单点登录接口:
@RequestMapping(value = "/login", method = RequestMethod.POST) public Map<String, Object> login(@RequestBody JSONObject json){ String loginName = json.optString("loginName"); String password = json.optString("password"); //校验用户名不能为空 if(StringUtils.isEmpty(loginName)){ return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_NAME_IS_NOT_EMPTY, null); } //校验用户密码不能为空 if(StringUtils.isEmpty(password)){ return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_PWD_CAN_NOT_BE_EMPTY, null); } //根据用户名查询数据库用户信息 User user = systemService.getBaseUserByLoginName(loginName); //用户名或密码不正确 if(null == user){ return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS, false); } boolean isValidate = systemService.validatePassword(password, user.getPassword()); if(!isValidate){ return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS, false); } if(isValidate){ //HttpSession session =request.getSession(false); Login login = new Login(user.getId(), user.getLoginName(), user.getPassword()); //给用户jwt加密生成token String token = JWT.sign(login, 60L* 1000L* 30L); Map<String,Object> result =new HashMap<String,Object>(); result.put("loginToken", token); result.put("userId", user.getId()); result.put("user", user); //保存用户信息到session //session.setAttribute(user.getId() + "@@" + token, user); //重建用户信息 this.rebuildLoginUser(user.getId(), token); return ResponseCode.buildReturnMap(ResponseCode.RESPONSE_CODE_LOGIN_SUCCESS, result); } return ResponseCode.buildReturnMap(ResponseCode.USER_LOGIN_PWD_ERROR, false); }
9. 测试sso单点登录:
返回结果集:
{ "message": "用户登录成功", "data": { "loginToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDkzODA1OTU0NTksInBheWxvYWQiOiJ7XCJ1aWRcIjpcIjExXCIsXCJsb2dpbk5hbWVcIjpcImFkbWluXCIsXCJwYXNzd29yZFwiOlwiZjU0NGQxM2QyY2EwNDU5ZGQ0ZTU1NzVjNmZkYWIzMzM0MzE1MWFlZjgwYmE5ZTNiN2U1ZjM2MzJcIn0ifQ.56L60WtxHXSu9vNs6XsWy5zbmc3kP_IWG1YpReK50DM", "userId": "11", "user": { "QQ":"2147775633", "id": "11", "isNewRecord": false, "remarks": "", "createDate": "2017-08-08 08:08:08", "updateDate": "2017-10-29 11:23:50", "loginName": "admin", "no": "00012", "name": "admin", "email": "2147775633@qq.com", "phone": "400000000", "mobile": "13888888888", "userType": "", "loginIp": "0:0:0:0:0:0:0:1", "loginDate": "2017-10-30 10:48:06", "loginFlag": "1", "photo": "", "idCard": "420888888888888888", "oldLoginIp": "0:0:0:0:0:0:0:1", "oldLoginDate": "2017-10-30 10:48:06", "roleNames": "", "admin": false } }, "code": 200 }
到此完毕!!
用java实施的电子商务平台太少了,使用spring cloud技术构建的b2b2c电子商务平台更少,大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B、B2C、C2C、O2O、新零售、直播电商等子平台。
相关推荐
SSO(Single Sign-On)...综上所述,这个项目通过整合Spring、SpringMVC、Interceptor、JWT和Redis,构建了一个高效、安全的SSO单点登录系统,使得用户在多应用环境中只需一次登录,即可畅游各个应用,提升了用户体验。
基于 SpringBoot + Spring + SpringMvc + Mybatis + Shiro+ Redis 开发单点登录管理系统 基于 SpringBoot + Spring + SpringMvc + Mybatis + Shiro+ Redis 开发单点登录管理系统 基于 SpringBoot + Spring + ...
Java基于Spring+SpringMVC+MyBatis实现的学生信息管理系统源码,SSM+Vue的学生管理系统。 Java基于Spring+SpringMVC+MyBatis实现的学生信息管理系统源码,SSM+Vue的学生管理系统。 Java基于Spring+SpringMVC+...
完善的Spring+SpringMVC+Mybatis+easyUI后台管理系统(RESTful API+redis).zip 完善的Spring+SpringMVC+Mybatis+easyUI后台管理系统(RESTful API+redis).zip 完善的Spring+SpringMVC+Mybatis+easyUI后台管理系统...
Spring+SpringMVC+MyBatis+Shiro+MySQL+Redis+Maven+EasyUI+Bootstrap实现的通用权限管理系统。 Spring+SpringMVC+MyBatis+Shiro+MySQL+Redis+Maven+EasyUI+Bootstrap实现的通用权限管理系统 Spring+SpringMVC+...
基于Spring+SpringMVC+Mybatis架构的博客系统:博客管理、图表数据、日志分析、访问记录、图库管理、资源管理、友链通知等。良好的页面预加载,无限滚动加载,文章置顶,博主推荐等。提供 用户端+管理端 的整套系统...
基于spring+springMvc+mybatis 开发的企业门户网站基于spring+springMvc+mybatis 开发的企业门户网站基于spring+springMvc+mybatis 开发的企业门户网站基于spring+springMvc+mybatis 开发的企业门户网站基于spring+...
基于SSM(Spring+SpringMVC+Mybatis)的新闻管理系统源码+数据库.zip 基于SSM(Spring+SpringMVC+Mybatis)的新闻管理系统源码+数据库.zip 基于SSM(Spring+SpringMVC+Mybatis)的新闻管理系统源码+数据库.zip 基于SSM...
yshop基于当前流行技术组合的前后端分离商城系统: SpringBoot2+MybatisPlus+SpringSecurity+jwt+redis+Vue的前后端分离的商城系统, 包含分类、sku、运费模板、素材库、小程序直播、拼团、砍价、商户管理、 秒杀、...
"Shiro+SpringMVC+Redis+MySQL实现单点登录"是一个典型的系统安全架构,它整合了多个技术组件来构建一个高效、可靠的单点登录(Single Sign-On, SSO)解决方案。以下是关于这个主题的详细知识点: 1. **Apache ...
基于Spring+SpringMVC+Mybaits的小区停车场车牌识别系统 基于Spring+SpringMVC+Mybaits的小区停车场车牌识别系统 基于Spring+SpringMVC+Mybaits的小区停车场车牌识别系统 基于Spring+SpringMVC+Mybaits的小区停车场...
酒店管理系统源码(spring+springmvc+mybatis) 酒店管理系统源码(spring+springmvc+mybatis) 酒店管理系统源码(spring+springmvc+mybatis) 酒店管理系统源码(spring+springmvc+mybatis) 酒店管理系统...
标题中的"idea工具创建的Spring+SpringMVC+Hibernate+maven项目"指的是使用IntelliJ IDEA这个集成开发环境(IDE)构建的一个Java Web项目,该项目整合了四个关键的技术框架:Spring、SpringMVC、Hibernate以及Maven...
基于IDEA+Spring+SpringMVC+Mybatis+Redis+Shiro+Maven实现的教务管理系统+源码,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用~ 基于IDEA+Spring+SpringMVC+...
本项目以“maven+springmvc+redis+mybatis整合”为主题,旨在提供一个基于这些技术的集成框架,特别强调了利用Redis作为缓存来提升应用性能。下面将详细阐述这个框架中的各个组成部分以及它们之间的协作。 首先,...
标题 "Spring+SpringMVC+Mybatis资源课件" 提供了一个学习路径,涉及Java开发中的三个关键组件:Spring框架、SpringMVC和Mybatis。这些技术是构建现代企业级Web应用程序的基础,尤其是在Java世界中。 Spring框架是...
Spring+SpringMVC+Hibernate 框架集成详解 本文档旨在详细介绍 Spring、SpringMVC 和 Hibernate 框架的集成,旨在帮助开发人员快速了解这三个框架的集成过程。 Spring 框架 Spring 框架是一个 Java 语言的开源...
大型电商项目实战1:Redis+Rest+Linux+Nginx+Spring+SpringMVC实现JAVA高并发秒杀系统,baidu链接,谢谢