目录
什么是单点登录系统?
单点登录的英文名叫做:Single Sign On(简称SSO)。
在以前,一般我们就单系统,所有的功能都在同一个系统上。
后来,我们为了合理利用资源和降低耦合性,于是把单系统拆分成多个子系统。
比如阿里系的淘宝和天猫,很明显地我们可以知道这是两个系统,但是你在使用的时候,登录了天猫,淘宝也会自动登录。
简单来说,单点登录就是在多个系统中,用户只需一次登录,各个系统即可感知该用户已经登录。
项目目录:
核心代码:主要是登录,登出,注册,登录校验功能
@RestController
@RequestMapping("/app")
public class AppController {
@Autowired
private UserService userService;
/**
* Login
*
* @param username
* @param password
* @return
*/
@RequestMapping("/login")
@ResponseBody
public ReturnT<String> login(String username, String password) {
// valid login
ReturnT<UserInfo> result = userService.findUser(username, password);
if (result.getCode() != ReturnT.SUCCESS_CODE) {
return new ReturnT<String>(result.getCode(), result.getMsg());
}
// 1、make xxl-sso user
XxlSsoUser xxlUser = new XxlSsoUser();
xxlUser.setUserid(String.valueOf(result.getData().getId()));
xxlUser.setUsername(result.getData().getUserName());
xxlUser.setVersion(UUID.randomUUID().toString().replaceAll("-", ""));
xxlUser.setExpireMinute(SsoLoginStore.getRedisExpireMinute());
xxlUser.setExpireFreshTime(System.currentTimeMillis());
// 2、generate sessionId + storeKey
String sessionId = SsoSessionIdHelper.makeSessionId(xxlUser);
// 3、login, store storeKey
SsoTokenLoginHelper.login(sessionId, xxlUser);
// 4、return sessionId
return new ReturnT<String>(sessionId);
}
/**
* Logout
*
* @param sessionId
* @return
*/
@RequestMapping("/logout")
@ResponseBody
public ReturnT<String> logout(String sessionId) {
// logout, remove storeKey
SsoTokenLoginHelper.logout(sessionId);
return ReturnT.SUCCESS;
}
/**
* logincheck
*
* @param token
* @return
*/
@RequestMapping("/logincheck")
@ResponseBody
public ReturnT<XxlSsoUser> logincheck(String token) {
// logout
XxlSsoUser xxlUser = SsoTokenLoginHelper.loginCheck(token);
if (xxlUser == null) {
return new ReturnT<XxlSsoUser>(ReturnT.FAIL_CODE, "sso not login.");
}
return new ReturnT<XxlSsoUser>(xxlUser);
}
@RequestMapping("/sign")
@ResponseBody
public ReturnT<Boolean> sign(@Validated @RequestBody UserSignParam userSignParam){
UserInfo userInfo = new UserInfo();
BeanUtils.copyProperties(userSignParam,userInfo);
return userService.signUser(userInfo);
}
}
配置文件相关参数:
context-path作用:所有接口前都带上/hongyan-sso一级目录
接口的三级路径:
第一路径是项目路径 就是这个context-path
第二路径是模块路径
第三路径是具体功能
active: local 表示用local配置文件(如果用test修改为active: test)
server:
port: 8089
servlet:
context-path: /hongyan-sso
spring:
application:
name: qcbysso
profiles:
active: local
freemarker:
templateLoaderPath: classpath:/templates/
suffix: .ftl
charset: UTF-8
request-context-attribute: request
settings.number_format: 0.##########
哈希环(算法):
哈希环(算法):如果说对数据移量敏感的服务,哈希策略必须选这个;对数据敏感的,不能用取余做哈希
数据移量敏感:比如数据储存在a机器,下次哈希还得存在a机器,不能存储到别的地方
/**
* 方式01: Redis单节点 + Jedis单例 : Redis单节点压力过重, Jedis单例存在并发瓶颈 》》不可用于线上
* new Jedis("127.0.0.1", 6379).get("cache_key");
* 方式02: Redis单节点 + JedisPool单节点连接池 》》 Redis单节点压力过重,负载和容灾比较差
* new JedisPool(new JedisPoolConfig(), "127.0.0.1", 6379, 10000).getResource().get("cache_key");
* 方式03: Redis分片(通过client端集群,一致性哈希方式实现) + Jedis多节点连接池 》》Redis集群,负载和容灾较好, ShardedJedisPool一致性哈希分片,读写均匀,动态扩充
* new ShardedJedisPool(new JedisPoolConfig(), new LinkedList<JedisShardInfo>());
* 方式04: Redis集群;
* new JedisCluster(jedisClusterNodes);
*/
方式01:
这个设计模式的瓶颈:服务端jedis 和单机redis 若任意一个出现问题,服务会终止,
方式02:
jedis采用集群,将瓶颈归于redis,用于项目简单,不需要高并发,存储的数据不敏感可以用
方式03和04:
jedis采用哈希 将数据存储到对应的redis上 有点:一致性哈希分片,读写均匀,动态扩充
多采用这种设计模式
池化思想:
典型的牺牲空间换取时间
例如:数据库连接池,jedis连接池,线程池等等,每次项目启动时先创建一些连接,可以直接用。因为创建连接是需要时间的(如果项目启动创建10条连接,需求只有1条,那么剩余的连接继续使用不回收)
为什么说ThreadLocal适合放用户信息
使用场景,就是用于线程之间上下文传递参数
从请求开始到返回,都是在一个线程里面执行的,所以我们可以用ThreadLocal适合存放用户信息.这样在这个请求过程中 我们可以在不同位置获取到存储的用户信息.