1. 程式人生 > >SSO單點登入-分散式系統實戰

SSO單點登入-分散式系統實戰

什麼是單點登入SSO(Single Sign-On)

SSO是一種統一認證和授權機制,指訪問同一伺服器不同應用中的受保護資源的同一使用者,只需要登入一次,即通過一個應用中的安全驗證後,再訪問其他應用中的受保護資源時,不再需要重新登入驗證。

單點登入解決了什麼問題

解決了使用者只需要登入一次就可以訪問所有相互信任的應用系統,而不用重複登入。例如CSDN中的論壇應用,部落格應用,下載應用模組。我們只要在CSDN中訪問任何一個子應用後,再訪問其他應用站點的時候就不需要在進行登入。

Sso系統工程搭建


使用者登入


效果演示:





核心程式碼:

登入:

package cn.e3mall.sso.service.impl;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import cn.e3mall.common.jedis.JedisClient;
import cn.e3mall.common.utils.E3Result;
import cn.e3mall.common.utils.JsonUtils;
import cn.e3mall.mapper.TbUserMapper;
import cn.e3mall.pojo.TbUser;
import cn.e3mall.pojo.TbUserExample;
import cn.e3mall.pojo.TbUserExample.Criteria;
import cn.e3mall.sso.service.LoginService;

/**
 * 使用者登入處理
 * <p>Title: LoginServiceImpl</p>
 * <p>Description: </p>
 * <p>Company: www.itcast.cn</p> 
 * @version 1.0
 */
@Service
public class LoginServiceImpl implements LoginService {

	@Autowired
	private TbUserMapper userMapper;
	@Autowired
	private JedisClient jedisClient;
	@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);
	}

}
package cn.e3mall.sso.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.e3mall.common.utils.CookieUtils;
import cn.e3mall.common.utils.E3Result;
import cn.e3mall.sso.service.LoginService;
/**
 * 使用者登入處理
 * <p>Title: LoginController</p>
 * <p>Description: </p>
 * <p>Company: www.itcast.cn</p> 
 * @version 1.0
 */
@Controller
public class LoginController {
	@Autowired
	private LoginService loginService;
	@Value("${TOKEN_KEY}")
	private String TOKEN_KEY;
	@RequestMapping("/page/login")
	public String showLogin() {
		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) {
			String token = e3Result.getData().toString();
			//如果登入成功需要把token寫入cookie
			System.out.println("token:"+token);
			CookieUtils.setCookie(request, response, TOKEN_KEY, token);
		}
		//返回結果
		return e3Result;
	}
}
package cn.e3mall.sso.service.impl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import cn.e3mall.common.jedis.JedisClient;
import cn.e3mall.common.utils.E3Result;
import cn.e3mall.common.utils.JsonUtils;
import cn.e3mall.pojo.TbUser;
import cn.e3mall.sso.service.TokenService;
/**
 * 根據token取使用者資訊
 * <p>Title: TokenServiceImpl</p>
 * <p>Description: </p>
 * <p>Company: www.itcast.cn</p> 
 * @version 1.0
 */
@Service
public class TokenServiceImpl implements TokenService {
	@Autowired
	private JedisClient jedisClient;
	@Value("${SESSION_EXPIRE}")
	private Integer SESSION_EXPIRE;
	@Override
	public E3Result getUserByToken(String token) {
		//根據token到redis中取使用者資訊
		String json = jedisClient.get("SESSION:" + token);
		//取不到使用者資訊,登入已經過期,返回登入過期
		if (StringUtils.isBlank(json)) {
			return E3Result.build(201, "使用者登入已經過期");
		}
		//取到使用者資訊更新token的過期時間
		jedisClient.expire("SESSION:" + token, SESSION_EXPIRE);
		//返回結果,E3Result其中包含TbUser物件
		TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
		return E3Result.ok(user);
	}
}
package cn.e3mall.sso.controller;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.e3mall.common.utils.E3Result;
import cn.e3mall.sso.service.TokenService;
/**
 * 根據token查詢使用者資訊Controller
 * <p>Title: TokenController</p>
 * <p>Description: </p>
 * <p>Company: www.itcast.cn</p> 
 * @version 1.0
 */
@Controller
public class TokenController {
	@Autowired
	private TokenService tokenService;
	
	/*@RequestMapping(value="/user/token/{token}", 
			produces=MediaType.APPLICATION_JSON_UTF8_VALUE"application/json;charset=utf-8")
	@ResponseBody
	public String getUserByToken(@PathVariable String token, String callback) {
		E3Result result = tokenService.getUserByToken(token);
		//響應結果之前,判斷是否為jsonp請求
		if (StringUtils.isNotBlank(callback)) {
			//把結果封裝成一個js語句響應
			return callback + "(" + JsonUtils.objectToJson(result)  + ");";
		}
		return JsonUtils.objectToJson(result);
	}*/
	@RequestMapping(value="/user/token/{token}")
	@ResponseBody
	public Object getUserByToken(@PathVariable String token, String callback) {
		E3Result result = tokenService.getUserByToken(token);
		//響應結果之前,判斷是否為jsonp請求
		if (StringUtils.isNotBlank(callback)) {
			//把結果封裝成一個js語句響應
			MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(result);
			mappingJacksonValue.setJsonpFunction(callback);
			return mappingJacksonValue;
		}
		return result;
	}
}