Sso系统工程搭建
服务接口实现:
用户登录:
功能分析:
请求的url:/user/login
请求的方法:POST
参数:username、password,表单提交的数据。可以使用方法的形参接收。
返回值:json数据,使用result包含一个token。
登录的业务流程:
登录的处理流程:
1、登录页面提交用户名密码。
2、登录成功后生成token。Token相当于原来的jsessionid,字符串,可以使用uuid。
3、把用户信息保存到redis。Key就是token,value就是TbUser对象转换成json。
4、使用String类型保存Session信息。可以使用“前缀:token”为key
5、设置key的过期时间。模拟Session的过期时间。一般半个小时。
6、把token写入cookie中。
7、Cookie需要跨域。例如www.imooc.com\sso.imooc.com\order.imooc.com,可以使用工具类。jsonp
8、Cookie的有效期。关闭浏览器失效。
9、登录成功。
Dao层:逆向工程
Service:
参数:
1、用户名:String username
2、密码:String password
返回值:result,包装token。
业务逻辑:
1、判断用户名密码是否正确。
2、登录成功后生成token。Token相当于原来的jsessionid,字符串,可以使用uuid。
3、把用户信息保存到redis。Key就是token,value就是TbUser对象转换成json。
4、使用String类型保存Session信息。可以使用“前缀:token”为key
5、设置key的过期时间。模拟Session的过期时间。一般半个小时。
6、返回Result包装token。
@Override
public result login(String username, String password) {
// 1、判断用户名密码是否正确。
TbUserExample example = new TbUserExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
//查询用户信息
List<TbUser> list = userMapper.selectByExample(example);
if (list == null || list.size() == 0) {
return result.build(400, "用户名或密码错误");
}
TbUser user = list.get(0);
//校验密码
if (!user.getPassword().equals(DigestUtils.md5DigestAsHex(password.getBytes()))) {
return result.build(400, "用户名或密码错误");
}
// 2、登录成功后生成token。Token相当于原来的jsessionid,字符串,可以使用uuid。
String token = UUID.randomUUID().toString();
// 3、把用户信息保存到redis Key就是token,value就是TbUser对象转换成json。
// 4、使用String类型保存Session信息。可以使用“前缀:token”为key
user.setPassword(null);
jedisClient.set(USER_INFO + ":" + token, JsonUtils.objectToJson(user));
// 5、设置key的过期时间。模拟Session的过期时间。一般半个小时。
jedisClient.expire(USER_INFO + ":" + token, SESSION_EXPIRE);
// 6、返回result包装token。
return result.ok(token);
}
jedisClient可以参考redis使用方法文章
Controller:
@RequestMapping(value="/user/login", method=RequestMethod.POST)
@ResponseBody
public Result login(String username, String password,
HttpServletRequest request, HttpServletResponse response) {
// 1、接收两个参数。
// 2、调用Service进行登录。
Result result = userService.login(username, password);
// 3、从返回结果中取token,写入cookie。Cookie要跨域。
String token = result.getData().toString();
CookieUtils.setCookie(request, response, COOKIE_TOKEN_KEY, token);
// 4、响应数据。Json数据。result,其中包含Token。
return result;
}
通过token查询用户信息
UserService:
@Override
public Result getUserByToken(String token) {
// 2、根据token查询redis。
String json = jedisClient.get(USER_INFO + ":" + token);
if (StringUtils.isBlank(json)) {
// 3、如果查询不到数据。返回用户已经过期。
return Result.build(400, "用户登录已经过期,请重新登录。");
}
// 4、如果查询到数据,说明用户已经登录。
// 5、需要重置key的过期时间。
jedisClient.expire(USER_INFO + ":" + token, 3600);
// 6、把json数据转换成TbUser对象,然后使用e3Result包装并返回。
TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
return Result.ok(user);
}
controller:
@RequestMapping("/user/token/{token}")
@ResponseBody
public Result getUserByToken(@PathVariable String token) {
Result result = userService.getUserByToken(token);
return result;
}
jsonp调用:
用户身份认证:
功能分析
1、使用springmvc的拦截器实现。需要实现一个接口HandlerInterceptor接口。
2、业务逻辑
a)从cookie中取token。
b)没有token,需要跳转到登录页面。
c)有token。调用sso系统的服务,根据token查询用户信息。(使用redis可以实现)
d)如果查不到用户信息。用户登录已经过期。需要跳转到登录页面。
e)查询到用户信息。放行。
拦截器实现:
public class LoginInterceptor implements HandlerInterceptor {
@Value("${TT_TOKEN}")
private String TT_TOKEN;
@Value("${SSO_LOGIN_URL}")
private String SSO_LOGIN_URL;
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//执行Handler之前执行此方法
// a)从cookie中取token。
String token = CookieUtils.getCookieValue(request, TT_TOKEN);
if (StringUtils.isBlank(token)) {
//取当前请求的url
String url = request.getRequestURL().toString();
// b)没有token,需要跳转到登录页面。
response.sendRedirect(SSO_LOGIN_URL + "?redirectUrl=" + url);
//拦截
return false;
}
// c)有token。调用sso系统的服务,根据token查询用户信息。
e3Result result = userService.getUserByToken(token);
if (result.getStatus() != 200) {
// d)如果查不到用户信息。用户登录已经过期。需要跳转到登录页面。
//取当前请求的url
String url = request.getRequestURL().toString();
// b)没有token,需要跳转到登录页面。
response.sendRedirect(SSO_LOGIN_URL + "?redirectUrl=" + url);
//拦截
return false;
}
// e)查询到用户信息。放行。
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 执行Handler之后返回ModelAndView之前
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 返回ModelAndView之后,执行。异常处理。
}
}
中springmvc.xml中配置拦截器。
<!-- 拦截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.imooc.cart.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
实现sso系统的回调
@RequestMapping("/{page}")
public String showPage(@PathVariable String page) {
return page;
}