current position:Home>[Java from Zero to Architect Season 3] [49] Session Management - Token_ehcache

[Java from Zero to Architect Season 3] [49] Session Management - Token_ehcache

2022-08-06 20:02:55lpruoyu


持续学习&持续更新中…

守破离


基于Cookie、Session

在这里插入图片描述

在这里插入图片描述

基于Token

在这里插入图片描述

在这里插入图片描述

ehcache

简单使用

在这里插入图片描述

依赖:

	<!-- 缓存 -->
	<dependency>
	    <groupId>org.ehcache</groupId>
	    <artifactId>ehcache</artifactId>
	</dependency>

标签:

    <!-- <persistence directory="F:/ehcache"/> -->
    
    <cache alias="test">
        <expiry>
            <!-- none:永不过期 -->
            <none/>
            <!-- tti:time to idle(空闲时间)=> 10月1号登录,默认10月8number will be invalid. 但是,如果10月3号登陆了,那么10月10number is invalid; 如果10月4logged in again,Then extend it7天,10月11number is invalid. 也就是说,只要7天内不访问,就失效. -->
            <!-- <tti unit="days">7</tti> -->
            <!-- ttl:time to live(存活时间)=> 10月1号登录,10月8number will be invalid -->
            <!-- <ttl unit="days">7</ttl> -->
        </expiry>
        <resources>
            <!-- <offheap unit="MB"/> 堆外内存 -->
            <!-- <disk unit="MB" persistent="true" /> 磁盘 需要搭配persistence标签 -->
            <heap unit="entries">1000</heap> <!-- into heap memory,In-heap memory isnewwhere the objects are stored -->
            <!-- <heap>1000</heap> unit="entries" 缓存个数 是默认的 -->
            <!-- <heap unit="MB">1000</heap> 缓存大小:GB、MB、KB、... -->
        </resources>
    </cache>

使用:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">

    <cache-template name="common">
        <key-type>java.lang.Object</key-type>
        <value-type>java.lang.Object</value-type>
        <resources>
            <heap>10000</heap>
        </resources>
    </cache-template>

    <!-- 11月1号~11月7号,11月8号过期 11月6号~11月12号,11月13号过期 11月12号~11月18号,11月19号过期 -->

    <!-- 存放token的缓存:只要7天内不访问,就失效 -->
    <cache alias="token" uses-template="common">
        <expiry>
            <tti unit="days">7</tti>
        </expiry>
    </cache>

    <!-- 默认缓存:永不过期 -->
    <cache alias="default" uses-template="common">
        <expiry>
            <none/>
        </expiry>
    </cache>
</config>
public class Caches {
    
    private static final CacheManager MGR;
    private static final Cache<Object, Object> DEFAULT_CACHE;
    private static final Cache<Object, Object> TOKEN_CACHE;
    static {
    
        // 初始化缓存管理器
        URL url = Caches.class.getClassLoader().getResource("ehcache.xml");
        assert url != null;
        Configuration cfg = new XmlConfiguration(url);
        MGR = CacheManagerBuilder.newCacheManager(cfg);
        MGR.init();

        // 缓存对象
        DEFAULT_CACHE = MGR.getCache("default", Object.class, Object.class);
        TOKEN_CACHE = MGR.getCache("token", Object.class, Object.class);
    }

    public static void put(Object key, Object value) {
    
        if (key == null || value == null) return;
        DEFAULT_CACHE.put(key, value);
    }

    public static void remove(Object key) {
    
        if (key == null) return;
        DEFAULT_CACHE.remove(key);
    }

    public static <T> T get(Object key) {
    
        if (key == null) return null;
        return (T) DEFAULT_CACHE.get(key);
    }

    public static void clear() {
    
        DEFAULT_CACHE.clear();
    }

    public static void putToken(Object key, Object value) {
    
        if (key == null || value == null) return;
        TOKEN_CACHE.put(key, value);
    }

    public static void removeToken(Object key) {
    
        if (key == null) return;
        TOKEN_CACHE.remove(key);
    }

    public static <T> T getToken(Object key) {
    
        if (key == null) return null;
        return (T) TOKEN_CACHE.get(key);
    }

    public static void clearToken() {
    
        TOKEN_CACHE.clear();
    }
}

项目使用:登录、登出

  • as long as7logged in days,就不会失效,就不用重新登录
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">

    <cache-template name="common">
        <key-type>java.lang.Object</key-type>
        <value-type>java.lang.Object</value-type>
        <resources>
            <heap>10000</heap>
        </resources>
    </cache-template>

    <!-- 11月1号~11月7号,11月8号过期 11月6号~11月12号,11月13号过期 11月12号~11月18号,11月19号过期 -->

    <!-- 存放token的缓存:只要7天内不访问,就失效 -->
    <cache alias="token" uses-template="common">
        <expiry>
            <tti unit="days">7</tti>
<!-- <tti unit="seconds">7</tti>-->
        </expiry>
        <listeners>
            <listener>
                <class>programmer.lp.jk.common.cache.TokenCacheListener</class>
                <!-- 异步回调 -->
                <event-firing-mode>ASYNCHRONOUS</event-firing-mode>
                <!-- Don't process events sequentially -->
                <event-ordering-mode>UNORDERED</event-ordering-mode>
                <!-- Which actions will trigger the listener:添加、过期、删除 -->
                <events-to-fire-on>CREATED</events-to-fire-on>
                <events-to-fire-on>EXPIRED</events-to-fire-on>
                <events-to-fire-on>REMOVED</events-to-fire-on>
            </listener>
        </listeners>
    </cache>

    <!-- 默认缓存:永不过期 -->
    <cache alias="default" uses-template="common">
        <expiry>
            <none/>
        </expiry>
    </cache>
</config>
public class TokenCacheListener implements CacheEventListener<Object, Object> {
    
    @Override
    public void onEvent(CacheEvent cacheEvent) {
    
        String token = (String) cacheEvent.getKey();
        switch (cacheEvent.getType()) {
    
            case CREATED: {
    // 添加了一个新的token(Indicates that a user has just logged in)
                SysUserDto user = (SysUserDto) cacheEvent.getNewValue();
                // for future pass usersid找到他对应的token
                Caches.put(user.getUser().getId(), token);
                break;
            }

            case EXPIRED:
            case REMOVED: {
     // tokenremoved or expired
                SysUserDto user = (SysUserDto) cacheEvent.getOldValue();
                Caches.remove(user.getUser().getId());
                break;
            }

            default: break;
        }
    }
}
@Override
    public RespLogin login(ReqLogin reqVo) {
    
        // 根据用户名查询用户
        MPLambdaQueryWrapper<SysUser> wrapper = new MPLambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, reqVo.getUsername());
        SysUser po = baseMapper.selectOne(wrapper);

        // 用户名不存在
        if (po == null) {
    
            return JSONResults.exception(CodeMsg.WRONG_USERNAME);
        }

        // 密码不正确
        if (!po.getPassword().equals(reqVo.getPassword())) {
    
            return JSONResults.exception(CodeMsg.WRONG_PASSWORD);
        }

        // 账号锁定
        if (po.getStatus() == Constants.SysUserStatus.LOCKED) {
    
            return JSONResults.exception(CodeMsg.USER_LOCKED);
        }

        /** 登录成功 **/

        // 更新登录时间
        po.setLoginTime(new Date());
        baseMapper.updateById(po);

        SysUserDto dto = new SysUserDto();
        dto.setUser(po);
        // 根据用户id查询所有的角色:sys_role,sys_user_role
        List<SysRole> roles = roleService.listByUserId(po.getId());

        // 根据角色id查询所有的资源:sys_resource、sys_role_resource
        if (!CollectionUtils.isEmpty(roles)) {
    
            dto.setRoles(roles);

            List<Short> roleIds = Streams.map(roles, SysRole::getId);
            List<SysResource> resources = resourceService.listByRoleIds(roleIds);
            dto.setResources(resources);
        }

        // 生成Token,发送Token给用户
        String token = UUID.randomUUID().toString();
        // 存储token到缓存中
        Caches.putToken(token, dto);

        // Specific data returned to the client
        RespLogin vo = MapStruct.INSTANCE.po2loginVo(po);
        vo.setToken(token);
        return vo;
    }
    @PostMapping("/logout")
    @ApiOperation("退出登录")
    public JSONResult logout(@RequestHeader(TokenFilter.HEADER_TOKEN) String token) {
    
        Caches.removeToken(token);
        return JSONResults.ok(CodeMsg.LOGOUT_OK);
    }
    @Override
    public boolean saveOrUpdate(ReqSaveSysUser entity) {
    
        // 转成PO
        SysUser po = MapStruct.INSTANCE.vo2po(entity);

        // 保存用户信息
        if (!saveOrUpdate(po)) return false;

        Integer id = entity.getId();
        if (id != null && id > 0) {
    // If it is an update
            // Remove successfully updated users from the cache(让token失效,用户必须重新登录)
            Caches.removeToken(Caches.get(id));
// Caches.remove(id);
            // Deletes all role information for the current user
            userRoleService.removeByUserId(entity.getId());
        }

        // 保存角色信息
        String roleIdsStr = entity.getRoleIds();
        if (Strings.isEmpty(roleIdsStr)) return true;

        String[] roleIds = roleIdsStr.split(",");
        List<SysUserRole> userRoles = new ArrayList<>();
        Integer userId = po.getId();
        for (String roleId : roleIds) {
     // 构建SysUserRole对象
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(Short.parseShort(roleId));
            userRoles.add(userRole);
        }
        return userRoleService.saveBatch(userRoles);
    }
// If the role information is updated, the user must log in again.
// Re-login is to check the user's permissions(资源),Let it cooperateShiro使用
    @Override
    public boolean saveOrUpdate(ReqSaveSysRole entity) {
    
        // 转成PO
        SysRole po = MapStruct.INSTANCE.vo2po(entity);

        // 保存角色信息
        if (!saveOrUpdate(po)) return false;

        Short id = entity.getId();
        if (id != null && id > 0) {
    
            MPLambdaQueryWrapper<SysUserRole> wrapper = new MPLambdaQueryWrapper<>();
            wrapper.select(SysUserRole::getUserId);
            wrapper.eq(SysUserRole::getRoleId, id);
            List<Object> userIds = userRoleMapper.selectObjs(wrapper);
            if (!CollectionUtils.isEmpty(userIds)) {
    
                for (Object userId : userIds) {
    
                    // Removes users with this role from the cache(让token失效,用户必须重新登录)
                    Caches.removeToken(Caches.get(userId));
                }
            }

            // Deletes all resource information for the current role
            roleResourceService.removeByRoleId(id);
        }

        // 保存角色信息
        String resourceIdsStr = entity.getResourceIds();
        if (Strings.isEmpty(resourceIdsStr)) return true;

        String[] resourceIds = resourceIdsStr.split(",");
        List<SysRoleResource> roleResources = new ArrayList<>();
        Short roleId = po.getId();
        for (String resourceId : resourceIds) {
     // 构建SysUserRole对象
            SysRoleResource roleResource = new SysRoleResource();
            roleResource.setRoleId(roleId);
            roleResource.setResourceId(Short.parseShort(resourceId));
            roleResources.add(roleResource);
        }
        return roleResourceService.saveBatch(roleResources);
    }

补充:A simple introduction to distributed architecture

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

参考

小码哥-李明杰: Java从0到架构师③进阶互联网架构师.


本文完,感谢您的关注支持!


copyright notice
author[lpruoyu],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/218/202208061954591586.html

Random recommended