1.1.1. 功能分析
请求的url:/user/login
请求的方法:POST
参数:username、password,表单提交的数据。可以使用方法的形参接收。
返回值:json数据,使用e3Result包含一个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.e3.com\sso.e3.com\order.e3.com,可以使用工具类。
8、Cookie的有效期。关闭浏览器失效。
9、登录成功。
1.1.1. Dao层
查询tb_user表。单表查询。可以使用逆向工程。
1.1.1. Service层
参数:
1、用户名:String username
2、密码:String password
返回值:e3Result,包装token。
业务逻辑:
1、判断用户名密码是否正确。
2、登录成功后生成token。Token相当于原来的jsessionid,字符串,可以使用uuid。
3、把用户信息保存到redis。Key就是token,value就是TbUser对象转换成json。
4、使用String类型保存Session信息。可以使用“前缀:token”为key
5、设置key的过期时间。模拟Session的过期时间。一般半个小时。
6、返回e3Result包装token。
/** * 用户登录service * @Auther: jun * @Date: 2018/5/31 0031 14:14 * @Description: */ @Service public class LoginServiceImpl implements LoginService { @Autowired private TbUserMapper tbUserMapper; @Autowired private JedisClient jedisClient; @Value("${SESSION_EXPIRE}") private Integer SESSION_EXPIRE; @Override public E3Result userLogin(String username, String password) { //业务逻辑: //1、判断用户名密码是否正确。 //先判断用户名是否存在 TbUserExample example=new TbUserExample(); TbUserExample.Criteria criteria = example.createCriteria(); //使用username作为查询条件 criteria.andUsernameEqualTo(username); List<TbUser> users = tbUserMapper.selectByExample(example); /*if (users==null && users.size()==0){ return E3Result.build(400,"用户名不存在"); }*/ if ( users.size()==0){ return E3Result.build(400,"用户名不存在"); } //取出用户信息 TbUser user = users.get(0); //取出的用户数据中判断用户输入对应的密码 if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) { return E3Result.build(400,"密码错误"); } //2、登录成功后生成token。Token相当于原来的jsessionid,字符串,可以使用uuid。 //生成的token是redis中对应的键 String token = UUID.randomUUID().toString(); //3、把用户信息保存到redis。Key就是token,value就是TbUser对象转换成json。 //不需要带密码 user.setPassword(null); jedisClient.set("SESSION:"+token,JsonUtils.objectToJson(user)); //4、使用String类型保存Session信息。可以使用“前缀:token”为key //5、设置key的过期时间。模拟Session的过期时间。一般一个小时。 jedisClient.expire("SESSION:"+token,SESSION_EXPIRE); //6、返回e3Result包装token。 return E3Result.ok(token); }
添加resources中一个applicationContent-redis.xml好使用redis缓存这里我们用的单机版redis
<!--连接池单机版--> <bean id="jedisClientPool" class="com.e3mall.common.jedis.JedisClientPool"> <property name="jedisPool" ref="jedisPool"/> </bean> <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg name="host" value="192.168.25.128"/> <constructor-arg name="port" value="6379"/> </bean>
applicationContent-service.xml发布服务
<!--登录服务--> <dubbo:service interface="com.e3mall.sso.service.LoginService" ref="loginServiceImpl" timeout="600000"/>
引用服务:
springmvc.xml中配置引用服务
<!--用户登录服务--> <dubbo:reference interface="com.e3mall.sso.service.LoginService" id="loginService" />
Controller
请求的url:/user/login
请求的方法:POST
参数:username、password,表单提交的数据。可以使用方法的形参接收。
HttpServletRequest、HttpServletResponse
返回值:json数据,使用e3Result包含一个token。
业务逻辑:
1、接收两个参数。
2、调用Service进行登录。
3、从返回结果中取token,写入cookie。Cookie要跨域。
/** * 用户登录功能Controller * @Auther: jun * @Date: 2018/5/31 0031 13:53 * @Description: */ @Controller public class LoginController { @Autowired private LoginService loginService; @Value("${TOKEN_KEY}") private String TOKEN_KEY; /** *跳转到登录页面 * @auther: jun * @date: 2018/5/31 0031 13:57 * @param * @return: java.lang.String * @Description: */ @RequestMapping("/page/login") public String showLogin(String redirect, Model model){ //把redirect参数传递到jsp页面 model.addAttribute("redirect",redirect); return "login"; } /** *用户登录并将用token写入cookie * @auther: jun * @date: 2018/5/31 0031 16:01 * @param username,password,request,response * @return: com.e3mall.common.utils.E3Result * @Description: */ @RequestMapping(value = "user/login",method = RequestMethod.POST) @ResponseBody public E3Result login(String username, String password, HttpServletRequest request, HttpServletResponse response){ //调用登录服务查询用户输入的用户名和密码是否存在数据库中并且是否正确 E3Result result = loginService.userLogin(username, password); //判断是否登录成功 if (result.getStatus()==200){ //登录成功需要将token写入cookie中 String token = result.getData().toString(); CookieUtils.setCookie(request,response,TOKEN_KEY,token); } //返回结果 return result; } }
登录成功并且redis有数据
1.1. 通过token查询用户信息
1.1.1. 功能分析
请求的url:/user/token/{token}
参数:Stringtoken需要从url中取。
返回值:json数据。使用e3Result包装Tbuser对象。
业务逻辑:
1、从url中取参数。
2、根据token查询redis。
3、如果查询不到数据。返回用户已经过期。
4、如果查询到数据,说明用户已经登录。
5、需要重置key的过期时间。
6、把json数据转换成TbUser对象,然后使用e3Result包装并返回。
1.1.1. Dao层
使用JedisClient对象。
1.1.1. Service层
参数:Stringtoken
返回值:e3Result
/** * token操作Service * @Auther: jun * @Date: 2018/5/31 0031 16:09 * @Description: */ @Service public class TokenServiceImpl implements TokenService { @Autowired private JedisClient jedisClient; @Value("${SESSION_EXPIRE}") private Integer SESSION_EXPIRE; @Override public E3Result getUserByToker(String token) { //根据token在redis中查询用户信息 String json = jedisClient.get("SESSION:" + token); //判断json数据是否为空 if (StringUtils.isBlank(json)) { //如果为空 return E3Result.build(201,"用户登录信息已经过期,请重新登录"); } //不为空说明查询到了数据,说明用户已经登录 //每次使用token访问是刷新过期时间设置过期时间 jedisClient.expire("SESSION:"+token,SESSION_EXPIRE); //获取到redis中token对应的用户信息 TbUser user = JsonUtils.jsonToPojo(json, TbUser.class); //返回结果 return E3Result.ok(user); } }
<!--token服务--> <dubbo:service interface="com.e3mall.sso.service.TokenService" ref="tokenServiceImpl" timeout="600000"/>
引用服务同上的登录服务一样引用
<!--token服务--> <dubbo:reference interface="com.e3mall.sso.service.TokenService" id="tokenService" />
Controller
/** * Token Controller * @Auther: jun * @Date: 2018/5/31 0031 16:18 * @Description: */ @Controller public class TokenController { @Autowired private TokenService tokenService; /** *请求的url:/user/token/{token} * 参数:String token需要从url中取。 * 返回值:json * @auther: jun * @date: 2018/5/31 0031 16:21 * @param token * @return: com.e3mall.common.utils.E3Result * @Description: */ /*@RequestMapping(value = "/user/token/{token}",method = RequestMethod.GET, produces =MediaType.APPLICATION_JSON_UTF8_VALUE *//*"application/json;charset=utf-8"*//*) @ResponseBody public String getUserByToken(@PathVariable String token,String callback){ //调用token服务 E3Result result = tokenService.getUserByToker(token); //响应结果之前,判断是否是jsonp请求(就是判断callback是否有值) if (StringUtils.isNoneBlank(callback)){ //瓶装成js语句需要的响应数据json数据 return callback+"("+JsonUtils.objectToJson(result)+");"; } //返回结果 return JsonUtils.objectToJson(result); }*/@RequestMapping(value = "/user/token/{token}",method = RequestMethod.GET) @ResponseBody public Object getUserByToken(@PathVariable String token,String callback){ //调用token服务 E3Result result = tokenService.getUserByToker(token); //响应结果之前,判断是否是jsonp请求(就是判断callback是否有值) if (StringUtils.isNoneBlank(callback)){ //瓶装成js语句响应 MappingJacksonValue mappingJacksonValue=new MappingJacksonValue(result); mappingJacksonValue.setJsonpFunction(callback); return mappingJacksonValue; } //返回结果 return result; } }
1.1.1. 安全退出
需要根据token删除redis中的key。
jsp页面
Service
@Override public E3Result logout(String token) { //执行删除 jedisClient.del ("SESSION:" + token); //返回成功 return E3Result.ok (); }
Controller这里退出我们选择了当前用户所有需要传一个token值
/** *需要根据token删除redis中的key * @auther: jun * @date: 2018/6/3 0003 21:17 * @param token * @return: com.e3mall.common.utils.E3Result * @Description: */ @RequestMapping(value = "user/logout/{token}") public String logout(@PathVariable String token){ tokenService.logout(token); return "redirect:/page/login.html"; }
删除token键
这里没有红框键了