目录
1.用户身份认证
在展示订单确认页面之前,需要对用户身份进行认证,要求用户必须登录。
1.1功能分析
- 使用springmvc的拦截器实现。需要实现一个接口HandlerInterceptor接口。
- 业务逻辑
- 从cookie中取token。
- 没有token,需要跳转到登录页面。
- 有token。调用sso系统的服务,根据token查询用户信息。
- 如果查不到用户信息。用户登录已经过期。需要跳转到登录页面。
- 查询到用户信息。放行。
- 在springmvc.xml中配置拦截器。
1.2拦截器实现
将一些常量放在properties文件中
#cookie中存放token的key
COOKIE_TOKEN_KEY=COOKIE_TOKEN_KEY
#sso服务url
SSO_URL=http://localhost:8088
拦截器是要实现HandlerInterceptor的,我们在taotao-order-web工程的src/main/java目录下新建一个包com.taotao.order.interceptor并在该包下新建LoginInterceptor拦截器(实现HandlerInterceptor)
package com.taotao.order.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.taotao.common.pojo.TaotaoResult;
import com.taotao.common.utils.CookieUtils;
import com.taotao.sso.service.UserLoginService;
public class LoginInterceptor implements HandlerInterceptor {
@Value("${SSO_URL}")
private String SSO_URL;
@Value("${COOKIE_TOKEN_KEY}")
private String COOKIE_TOKEN_KEY;
@Autowired
private UserLoginService loginService;
/**在进入目标方法之前执行*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//1.从cookie中获取token
String token = CookieUtils.getCookieValue(request, COOKIE_TOKEN_KEY);
if(StringUtils.isEmpty(token)) {
//2.用户未登录,重定向到登陆页面
response.sendRedirect(SSO_URL+"/page/login");
}
TaotaoResult result = loginService.getUserByToken(token);
if(result.getStatus()!=200) {
//3.用户已过期,重定向到登陆页面
response.sendRedirect(SSO_URL+"/page/login");
}else {
//4.用户已登录放行
return true;
}
return false;
}
/**在进入目标方法之后,在返回modelandview之前执行*/
/**共用变量的一些设置*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
/**返回modelandview之后,渲染到页面之前*/
/**异常处理 ,清理工作*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
配置拦截器
<!-- 配置用户身份认证的拦截器拦截订单确认和订单相关的处理 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- ** 表示当前路径及其子路径 * 只是拦截当前路径-->
<mvc:mapping path="/order/**"/>
<bean class="com.taotao.order.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
1.3测试访问
未登录状态下,结算购物车
被拦截后,重定向到登陆界面
2.拦截器存在的问题
存在两个问题:
- 调用SSO服务调用了两次,分别是在拦截器中调用一次,在controller获取用户信息又调用一次。
- 登录成功后跳转到了首页,应当跳转到订单确认页面才对。
2.1解决调用SSO服务两次的问题
实际上,只需要在拦截器中调用一次便可以了,调用之后,将用户信息的数据存放在request域中,等进入目标的方法,可以直接通过request域获取用户信息。
在拦截器中,将登录的用户TbUser对象放到request域中
从request域中获取TbUser对象
2.2解决登录之后跳转到首页的问题
当用户结算购物车的时候,需要登录,登录之后应当跳转到订单确认页面,不应该回到首页。
下面是正常的流程
在taotao-sso-web的login.jsp,我们可以看到一个叫做redirectUrl的变量,如果redirectUrl不为空,就会location.href=redirectUrl,
跳转到这个redirectUrl,所以我们可以在拦截器拦截未登录用户跳转http://localhost:8088/page/login时,设置一个参数redirect=http://localhost:8092/order/order-cart.html
比如:
http://localhost:8088/page/login?redirect=http://localhost:8092/order/order-cart.html
然后在taotao-sso-web的controller将redirect接收,并放到model中。
修改taotao-order-web的未登录用户拦截器,在跳转/page/login时加上参数redirect=url
这个地方是request.getRequestURL()不是request.getRequestURI(),小心看走眼
request.getRequestURL()获取请求的全名,包括协议、域名、ip、端口等
request.getRequestURI()只能获取端口后的相对路径
在taotao-sso-web系统中的controller中接收参数redirect,并放到model中
@RequestMapping("/page/{page}")
public String showPage(@PathVariable String page,String redirect,Model model) {
model.addAttribute("redirect", redirect);
return page;
}
2.3测试访问
启动工程
未登录状态下去结算
可以看到url后面的参数
登录成功跳转到订单确认页