项目7_ssm_宜立方商城_day11

本文介绍了一种基于SSO的单点登录系统实现方法,包括用户注册、登录验证及会话管理等关键环节,着重讲解了如何利用Redis存储用户会话信息及Token的生成与验证过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要使用单点登录系统:解决的是分布式环境中Session共享的问题

用户注册

检查数据是否可用
1.1.功能分析


请求的url:/user/check/{param}/{type}
参数:从url中取参数1、String param(要校验的数据)2、Integer type(校验的数据类型     数据类型:int type(1、2、3分别代表username、phone、email))
响应的数据:json数据。e3Result,封装的数据校验的结果true:成功false:失败

public interface RegisterService {
	E3Result checkData(String param,int type);
}
@Service
public class RegisterServiceImpl implements RegisterService {

	@Autowired
	private TbUserMapper userMapper;
	
	public E3Result checkData(String param, int type) {

		TbUserExample example=new TbUserExample();
		Criteria criteria = example.createCriteria();
		if(type ==1){
			criteria.andUsernameEqualTo(param);
		}else if(type ==2){
			criteria.andPhoneEqualTo(param);
		}else if(type ==3){
			criteria.andEmailEqualTo(param);
		}else{
			E3Result.build(400, "数据类型错误");
		}
		List<TbUser> list = userMapper.selectByExample(example);
		if(list !=null && list.size()>0){
			//如果有数据返回false
			return E3Result.ok(false);
		}
		//如果没有数据返回true
		return E3Result.ok(true);
	}
}
//用户注册
@Controller
public class RegisterController {

@Autowired
private RegisterService service;

@RequestMapping("user/check/{param}/{type}")
@ResponseBody
public E3Result checkData(@PathVariable String param,@PathVariable Integer type){
	E3Result e3result=service.checkData(param,type);
	return e3result;
}

用户注册

序列化:将表单数据变成key-value的字符串

E3Result register(TbUser user);
public E3Result register(TbUser user) {
	if(StringUtils.isBlank(user.getUsername())|| StringUtils.isBlank(user.getPassword()) 
			|| StringUtils.isBlank(user.getPhone())){
		return E3Result.build(400, "用户数据不完整,注册失败!!");
	}
	
	E3Result result=checkData(user.getUsername(), 1);

	//判断是否为true或者false
	if(!(boolean) result.getData()){
		return E3Result.build(400,"用户名已经被占用");
	}
	
	result=checkData(user.getPhone(), 2);
	if(!(boolean) result.getData()){
		return E3Result.build(400,"此手机号已经被占用");
	}
	
	user.setCreated(new Date());
	user.setUpdated(new Date());
	
	String md5 = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
	user.setPassword(md5);
	userMapper.insert(user);
	return E3Result.ok();
}
@RequestMapping(value="/user/register",method=RequestMethod.POST)
@ResponseBody
public E3Result register(TbUser user){
	E3Result e3result=service.register(user);
	return e3result;
}

spring自带一个md5加密

DigestUtils.md5DigestAsHex(user.getPassword().getBytes())

用户登录

跳转到登录页面

@Controller
public class LoginController {
	@RequestMapping("/page/login")
	public String toLogin(){
		return "login";
	}
}

登录的处理流程:(SSO单点登录)

  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. 登录成功。

public interface LoginService {
	/**
		1.判断用户名和密码是否正确
		2.如果不正确,返回登录失败
		3.如果正确生成token
		4.把用户名写入redis,key:token value:用户信息
		5.设置session的过期时间
		6.把token返回
	 */
	//返回值:E3Result,其中包含token信息
	E3Result userLogin(String username,String password);

}
@Service
public class LoginServiceImpl implements LoginService {

	@Autowired
	private JedisClient JedisClient;
	
	@Autowired
	private TbUserMapper userMapper;
	
	@Value("${SESSION_EXPIRE}")
	private Integer SESSION_EXPIRE;
	@Override
	public E3Result userLogin(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 E3Result.build(400, "用户名或密码错误");
		}
		//取用户信息
		TbUser user=list.get(0);
		//判断密码是否正确
		if(!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())){
			//2.返回登录页面
			return E3Result.build(400, "用户名或密码错误");
		}
		
		//3.如果正确生成token
		String  token=UUID.randomUUID().toString();
		//4.把用户名写入redis,key:token value:用户信息
		//密码不要带到客户端  密码在服务器端处理
		user.setPassword(null);
		JedisClient.set("SESSION:"+token, JsonUtils.objectToJson(user));
		//5.设置session的过期时间   时间是秒
		JedisClient.expire("SESSION:"+token, SESSION_EXPIRE);
		//6.把token返回
		return E3Result.ok(token);
	}

}

Cookie的工具类

package cn.e3mall.common.utils;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * 
 * Cookie 工具类
 *
 */
public final class CookieUtils {

    /**
     * 得到Cookie的值, 不编码
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName) {
        return getCookieValue(request, cookieName, false);
    }

    /**
     * 得到Cookie的值,
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, boolean isDecoder) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    if (isDecoder) {
                        retValue = URLDecoder.decode(cookieList[i].getValue(), "UTF-8");
                    } else {
                        retValue = cookieList[i].getValue();
                    }
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 得到Cookie的值,
     * 
     * @param request
     * @param cookieName
     * @return
     */
    public static String getCookieValue(HttpServletRequest request, String cookieName, String encodeString) {
        Cookie[] cookieList = request.getCookies();
        if (cookieList == null || cookieName == null) {
            return null;
        }
        String retValue = null;
        try {
            for (int i = 0; i < cookieList.length; i++) {
                if (cookieList[i].getName().equals(cookieName)) {
                    retValue = URLDecoder.decode(cookieList[i].getValue(), encodeString);
                    break;
                }
            }
        } catch (UnsupportedEncodingException e) {
        	 e.printStackTrace();
        }
        return retValue;
    }

    /**
     * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue) {
        setCookie(request, response, cookieName, cookieValue, -1);
    }

    /**
     * 设置Cookie的值 在指定时间内生效,但不编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage) {
        setCookie(request, response, cookieName, cookieValue, cookieMaxage, false);
    }

    /**
     * 设置Cookie的值 不设置生效时间,但编码
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, boolean isEncode) {
        setCookie(request, response, cookieName, cookieValue, -1, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage, boolean isEncode) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, isEncode);
    }

    /**
     * 设置Cookie的值 在指定时间内生效, 编码参数(指定编码)
     */
    public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String cookieValue, int cookieMaxage, String encodeString) {
        doSetCookie(request, response, cookieName, cookieValue, cookieMaxage, encodeString);
    }

    /**
     * 删除Cookie带cookie域名
     */
    public static void deleteCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName) {
        doSetCookie(request, response, cookieName, "", -1, false);
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     * 
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else if (isEncode) {
                cookieValue = URLEncoder.encode(cookieValue, "utf-8");
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 设置域名的cookie
            	String domainName = getDomainName(request);
            	System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                	cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
        	 e.printStackTrace();
        }
    }

    /**
     * 设置Cookie的值,并使其在指定时间内生效
     * 
     * @param cookieMaxage cookie生效的最大秒数
     */
    private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName, String cookieValue, int cookieMaxage, String encodeString) {
        try {
            if (cookieValue == null) {
                cookieValue = "";
            } else {
                cookieValue = URLEncoder.encode(cookieValue, encodeString);
            }
            Cookie cookie = new Cookie(cookieName, cookieValue);
            if (cookieMaxage > 0)
                cookie.setMaxAge(cookieMaxage);
            if (null != request) {// 设置域名的cookie
            	String domainName = getDomainName(request);
            	System.out.println(domainName);
                if (!"localhost".equals(domainName)) {
                	cookie.setDomain(domainName);
                }
            }
            cookie.setPath("/");
            response.addCookie(cookie);
        } catch (Exception e) {
        	 e.printStackTrace();
        }
    }

    /**
     * 得到cookie的域名
     */
    private static final String getDomainName(HttpServletRequest request) {
        String domainName = null;

        String serverName = request.getRequestURL().toString();
        if (serverName == null || serverName.equals("")) {
            domainName = "";
        } else {
            serverName = serverName.toLowerCase();
            serverName = serverName.substring(7);
            final int end = serverName.indexOf("/");
            serverName = serverName.substring(0, end);
            final String[] domains = serverName.split("\\.");
            int len = domains.length;
            if (len > 3) {
                // www.xxx.com.cn
                domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1];
            } else if (len <= 3 && len > 1) {
                // xxx.com or xxx.cn
                domainName = "." + domains[len - 2] + "." + domains[len - 1];
            } else {
                domainName = serverName;
            }
        }

        if (domainName != null && domainName.indexOf(":") > 0) {
            String[] ary = domainName.split("\\:");
            domainName = ary[0];
        }
        return domainName;
    }

}

 

@Controller
public class LoginController {
	
	@Autowired
	private LoginService loginService;
	
	@Value("${TOKEN_KEY}")
	private String TOKEN_KEY;
	@RequestMapping("/page/login")
	public String toLogin(){
		return "login";
	}

	@RequestMapping(value="/user/login", method=RequestMethod.POST)
	@ResponseBody
	public E3Result login(String username,String password,HttpServletRequest request,HttpServletResponse response){
		E3Result e3Result = loginService.userLogin(username, password);
		//判断是否登录成功
		if(e3Result.getStatus()==200){
			//如果登录成功需要把token写入cookie   Cookie要跨域。 cookie有名称和值
			String token = e3Result.getData().toString();
			// cookie中保存的token的key写在配置文件中
			CookieUtils.setCookie(request, response,TOKEN_KEY, token);
		}
		//返回结果
		return e3Result;
	}
	
}

测试登录功能是否好使

根据token取用户信息,回显给页面

通过token查询用户信息

请求的url:/user/token/{token}
参数:String token需要从url中取。
返回值:json数据。使用e3Result包装Tbuser对象。
业务逻辑:
1、从url中取参数。
2、根据token查询redis。
3、如果查询不到数据。返回用户已经过期。
4、如果查询到数据,说明用户已经登录。
5、需要重置key的过期时间。
6、把json数据转换成TbUser对象,然后使用e3Result包装并返回。

//根据token查询用户信息
public interface TokenService {
	E3Result getUserByToken(String token);
}
@Service
public class TokenServiceImpl implements TokenService {

	@Autowired
	private JedisClient jedisClient;
	@Value("${SESSION_EXPIRE}")
	private Integer SESSION_EXPIRE;
	
	public E3Result getUserByToken(String token) {
		// 1、根据token查询redis。
		String json = jedisClient.get("SESSION:"+token);
		if(StringUtils.isBlank(json)){
			// 2、如果查询不到数据。返回用户已经过期。
			return E3Result.build(205, "用户登录已经过期,请重新登录。");
		}
		// 3、如果查询到数据,说明用户已经登录。
		// 4、需要重置key的过期时间。
		jedisClient.expire( "SESSION:" + token, SESSION_EXPIRE);
		// 5、把json数据转换成TbUser对象,然后使用e3Result包装并返回。
		TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
		return E3Result.ok(user);
	}
}
@Controller
public class TokenController {
	@Autowired
	private TokenService service;
	
	@RequestMapping("/user/token/{token}")
	@ResponseBody
	public E3Result getUserByToken(@PathVariable String token){
		E3Result e3Result=service.getUserByToken(token);
		return e3Result;
	}
}

测试

1.使用js从cookie中取token

2.ajax请求接口 /user/token/{token}

3.得到json数据,并将用户名解析出来

4.把用户名显示到页面

jquery提供的工具,方便js从cookie中取数据的 

  这个内容是在e3mall.js里面的

首页展示用户名

方案一:在Controller中取cookie中的token数据,调用sso服务查询用户信息。(每个都要写,费劲)
方案二:当页面加载完成后使用js取token的数据,使用ajax请求查询用户信息。

Js不可以跨域请求数据。
什么是跨域:
1、域名不同
2、域名相同端口不同。

解决js的跨域问题可以使用jsonp。

Jsonp不是新技术,跨域的解决方案。使用js的特性绕过跨域请求。Js可以跨域加载js文件

改造TokenController(响应的是application/json)

用的spring是4.1以后的版本,也可以用以下方法写

效果显示

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guoyebing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值