单点登录主要问题在于多台服务器集群时,用户登录身份信息在每台服务器上是否能够保证都存在或者进行身份识别。
常用一下三种方式解决:
1、tomcat session 复制(服务器集群数量很多时,服务器之间相互复制,性能开销很大)
2、spring session session共享(有状态服务)
springSessionRepositoryFilter org.springframework.web.filter.DelegatingFilterProxy springSessionRepositoryFilter /*
redis.clients jedis 2.9.0 org.springframework.session spring-session-data-redis 2.0.1.RELEASE org.apache.commons commons-pool2 2.4.2
import javax.servlet.http.HttpServletRequest; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class IndexController { @RequestMapping("/index") @ResponseBody public String index(HttpServletRequest request,@Param(value = "name") String name,@Param(value = "password") String password) { request.getSession().setAttribute(name, password); return "success"; } @GetMapping("/getPassword") @ResponseBody public String getPassword(HttpServletRequest request,@Param(value = "name") String name) { return String.valueOf(request.getSession().getAttribute(name)); } }
3、jwt (JSON Web Token)(无状态服务,分布式系统中常用方案)
com.auth0 java-jwt 3.4.0
import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.gupao.model.User; public class JwtTokenUtils { public static String getToken(User user) { String token=JWT.create().withAudience(user.getId()+"").sign(Algorithm.HMAC256(user.getPassword())); return token; } }
import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.gupao.controller.BaseController; import com.gupao.jwt.PassToken; import com.gupao.jwt.UserLoginToken; import com.gupao.model.User; import com.gupao.service.UserService; public class TokenInterceptor implements HandlerInterceptor { @Autowired UserService userService; public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getHeader("token"); if (!(handler instanceof HandlerMethod)) { return true; } HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); if (method.isAnnotationPresent(PassToken.class)) { PassToken passToken = method.getAnnotation(PassToken.class); if (passToken.required()) { return true; } } // if(method.isAnnotationPresent(UserLoginToken.class)) { // UserLoginToken userLoginToken=method.getAnnotation(UserLoginToken.class); // if(userLoginToken.required()) { if(token==null) { throw new RuntimeException("无token,请重新登录!"); } String uid=JWT.decode(token).getAudience().get(0); Integer userId=Integer.valueOf(uid); User user=userService.findUserById(userId); if(user==null) { throw new RuntimeException("用户不存在!"); } JWTVerifier verifier=JWT.require(Algorithm.HMAC256(user.getPassword())).build(); try { verifier.verify(token); Object bean=handlerMethod.getBean(); if(bean instanceof BaseController) { BaseController baseController=(BaseController) bean; baseController.setUid(user.getId()+""); } } catch (Exception e) { throw new RuntimeException("401"); } return true; // } // } // 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 { } }
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface PassToken { boolean required() default true; }