一套简单的登录鉴权工具
前言
无论是SpringSecruity、Shiro,对于一些小项目来说都太过复杂,有些情况下我们就想使用简单的登录、鉴权功能,本文记录手写一套简单的登录、鉴权工具
思路
1、封装工具类,集成查询系统用户、系统角色,根据登录用户权限进行当前URL请求鉴权
2、在拦截器中调用工具类进行鉴权,通过放行、不通过则抛出对应业务异常信息
首先需要三张基础表:系统用户表、系统角色表、用户角色关联表 -- ---------------------------- -- Table structure for sys_user -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "表id", `nick_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "昵称", `user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "账号", `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "密码", PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = "系统用户表" ROW_FORMAT = Compact; -- ---------------------------- -- Records of sys_user -- ---------------------------- INSERT INTO `sys_user` VALUES ("1", "系统管理员", "admin", "000000"); INSERT INTO `sys_user` VALUES ("2", "张三-部门经理", "zhangsan", "111111"); INSERT INTO `sys_user` VALUES ("3", "小芳-前台接待", "xiaofang", "222222"); -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "表id", `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "角色名称", `role_menu` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT "角色菜单可视权限(可以不关联菜单,单独做成菜单管理直接与用户关联)", `role_url` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT "角色URL访问权限", PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = "系统角色表" ROW_FORMAT = Compact; -- ---------------------------- -- Records of sys_role -- ---------------------------- INSERT INTO `sys_role` VALUES ("1", "管理员", "[{"menuName":"系统管理","menuPath":"/sys/xtgl"},{"menuName":"用户管理","menuPath":"/sys/yhgl"},{"menuName":"网站门户管理","menuPath":"/portal/mhgl"}]", "/sys/*,/portal/mhgl,/getLoginUser"); INSERT INTO `sys_role` VALUES ("2", "部门领导", "[{"menuName":"用户管理","menuPath":"/sys/yhgl"},{"menuName":"网站门户管理","menuPath":"/portal/mhgl"}]", "/sys/yhgl,/portal/mhgl,/getLoginUser"); INSERT INTO `sys_role` VALUES ("3", "普通员工", "[{"menuName":"网站门户管理","menuPath":"/portal/mhgl"}]", "/portal/mhgl,/getLoginUser"); -- ---------------------------- -- Table structure for sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role` ( `id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT "表id", `user_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "用户id", `role_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT "角色id", PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = "系统用户-角色关联表" ROW_FORMAT = Compact; -- ---------------------------- -- Records of sys_user_role -- ---------------------------- INSERT INTO `sys_user_role` VALUES ("1", "1", "1"); INSERT INTO `sys_user_role` VALUES ("2", "1", "2"); INSERT INTO `sys_user_role` VALUES ("3", "1", "3"); INSERT INTO `sys_user_role` VALUES ("4", "2", "2"); INSERT INTO `sys_user_role` VALUES ("5", "3", "3");
在工具类中定义三个实体类方便传参接参(如果嫌麻烦也可以直接使用Map对象),使用自定义DbUtil查询数据库表数据(此操作,应交由项目ORM框架负责) 代码编写
DbUtil工具类package cn.huanzi.qch.util; import java.sql.*; import java.util.ArrayList; import java.util.HashMap; /** * 原生jdbc操作数据库工具类 */ public class DbUtil { //数据库连接:地址、用户名、密码 private final String url; private final String username; private final String password; //Connection连接实例 private Connection connection; public DbUtil(String url, String username, String password){ this.url = url; this.username = username; this.password = password; } public DbUtil(String url, String username, String password, String driver){ this(url,username,password); //加载驱动 try { /* 同时需要引入相关驱动依赖 1、MySQL: com.mysql.cj.jdbc.Driver 2、Oracle: oracle.jdbc.driver.OracleDriver 3、pgsql: org.postgresql.Driver */ Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 获取 Connection 连接 */ private Connection getConnection() { if(connection == null){ try { connection= DriverManager.getConnection(url, username, password); connection.setAutoCommit(true); } catch (SQLException e) { System.err.println("获取Connection连接异常..."); e.printStackTrace(); } } return connection; } /** * 设置是否自动提交事务 * 当需要进行批量带事务的操作时,关闭自动提交手动管理事务,将会大大提高效率! */ public void setAutoCommit(boolean autoCommit){ try { this.getConnection().setAutoCommit(autoCommit); } catch (SQLException e) { e.printStackTrace(); } } /** * 关闭自动提交事务时,需要手动管理事务提交、回滚 */ public void commit(){ try { this.getConnection().commit(); } catch (SQLException e) { e.printStackTrace(); } } public void rollback(){ try { this.getConnection().rollback(); } catch (SQLException e) { e.printStackTrace(); } } /** * 关闭 Connection 连接 */ public void close(){ if(connection != null){ try { connection.close(); connection = null; } catch (SQLException e) { System.err.println("关闭Connection连接异常..."); e.printStackTrace(); } } } /** * 查询 * 查询语句 */ public ArrayList> find(String sql, Object[] params) { ArrayList> list = new ArrayList<>(); //获取连接 Connection conn = this.getConnection(); PreparedStatement ps; ResultSet rs; try { //设置SQL、以及参数 ps = conn.prepareStatement(sql); if (params != null) { for (int i = 0; i < params.length; i++) { ps.setObject(i + 1, params[i]); } } //执行查询 rs = ps.executeQuery(); //获取查询结果 ResultSetMetaData rm = rs.getMetaData(); int columnCount = rm.getColumnCount(); //封装结果集 while (rs.next()) { HashMap map = new HashMap<>(columnCount); for (int i = 1; i <= columnCount; i++) { String name = rm.getColumnName(i).toLowerCase(); Object value = rs.getObject(i); map.put(name,value); } list.add(map); } } catch (Exception e) { System.err.println("执行 jdbcUtil.find() 异常..."); e.printStackTrace(); } return list; } public HashMap findOne(String sql, Object[] params){ ArrayList> list = this.find(sql, params); return list.size() > 0 ? list.get(0) : null; } public ArrayList> find(String sql) { return this.find(sql,null); } public HashMap findOne(String sql) { return this.findOne(sql,null); } /** * 执行 * 新增/删除/更新 等SQL语句 */ public boolean execute(String sql, Object[] params){ boolean flag = false; //获取连接 Connection conn = this.getConnection(); PreparedStatement ps; try { //设置SQL、以及参数 ps = conn.prepareStatement(sql); if (params != null) { for (int i = 0; i < params.length; i++) { ps.setObject(i + 1, params[i]); } } //执行 flag = ps.execute(); } catch (SQLException e) { System.err.println("执行 jdbcUtil.update() 异常..."); e.printStackTrace(); } return flag; } public boolean execute(String sql){ return this.execute(sql,null); } }
SecurityUtil工具类package cn.huanzi.qch.util; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; /** * 一套简单的登录、鉴权工具 */ public class SecurityUtil { /** * 单例模式-饿汉 */ private static final SecurityUtil instance = new SecurityUtil(); private SecurityUtil (){} public static SecurityUtil getInstance() { return instance; } /** * 无需登录即可访问的URL * PS:建议从配置文件读取 */ private static final String[] URLS = { //登录页、登录请求、注销请求 "/loginPage", "/login", "/logout", //静态资源,例如:js、css等 "/assets/**", //一些特殊无需权限控制的地址、api "/portal/index", }; /** * 用户角色信息一般情况下是不轻易更改,可以将结果存储到缓存对象 */ private static HashMap> userRoleMap = new HashMap<>(10); //查询数据库操作,应交由项目ORM框架负责 private final DbUtil dbUtil = new DbUtil("jdbc:mysql://localhost/jfinal_demo","root","123456"); /** * 鉴权中心 * PS:返回值类型有待商榷 */ public String auc(HttpServletRequest request){ //请求URL地址 String requestUri = request.getRequestURI(); SecurityUtil securityUtil = SecurityUtil.getInstance(); //是否为无需登录即可访问URL if(SecurityUtil.checkUrl(requestUri,SecurityUtil.URLS)){ //允许访问! return "SUCCEED"; } //是否为登录用户 SecurityUtil.User loginUser = securityUtil.getLoginUser(request); if(loginUser == null){ //未登录或登录凭证过期! return "UNAUTHORIZED"; } //该登录用户是否有权访问当前URL if(!SecurityUtil.checkUrl(requestUri,securityUtil.getRoleUrlByUserId(loginUser.getId()))){ //抱歉,你无权限访问! return "FORBIDDEN"; } //允许访问! return "SUCCEED"; } /** * 检查requestUri是否包含在urls中 */ public static boolean checkUrl(String requestUri,String[] urls){ //对/进行特殊处理 if("/".equals(requestUri) && !Arrays.asList(urls).contains(requestUri)){ return false; } String[] requestUris = requestUri.split("/"); for (String url : urls) { if (check(requestUris, url.split("/"))) { return true; } } return false; } private static boolean check(String[] requestUris,String[] urls){ for (int i1 = 0; i1 < requestUris.length; i1++) { //判断长度 if (i1 >= urls.length){ return false; } //处理/*、/**情况 if("**".equals(urls[i1])){ return true; } if("*".equals(urls[i1])){ continue; } //处理带后缀 if(requestUris[i1].contains(".") && urls[i1].contains(".")){ String[] split = requestUris[i1].split("."); String[] split2 = urls[i1].split("."); // *.后缀的情况 if("*".equals(split2[0]) && split[1].equals(split2[1])){ return true; } } //不相等 if(!requestUris[i1].equals(urls[i1])){ return false; } } return true; } /** * 从request设置、获取当前登录用户 * PS:登录用户可以放在session中,也可以做做成jwt */ public void setLoginUser(HttpServletRequest request,User loginUser){ request.getSession().setAttribute("loginUser",loginUser); } public User getLoginUser(HttpServletRequest request){ return (User)request.getSession().getAttribute("loginUser"); } public List getLoginUserRole(HttpServletRequest request){ User loginUser = this.getLoginUser(request); return loginUser != null ? getRoleByUserId(loginUser.getId()) : null; } /** * 根据用户id,获取用户允许访问URL */ public String[] getRoleUrlByUserId(String userId){ StringBuilder roleUrl = new StringBuilder(); for (SecurityUtil.Role role : this.getRoleByUserId(userId)) { roleUrl.append(",").append(role.getRoleUrl()); } return roleUrl.toString().split(","); } /** * 获取用户、用户角色 * PS:这些查询数据库操作,应交由项目ORM框架负责 */ public User getUserByUserNameAndPassword(String username,String password){ //PS:密码应该MD5加密后密文存储,匹配时先MD5加密后匹配,本例中存储的是明文,就不进行MD5加密了 User user = null; HashMap map = dbUtil.findOne("select * from sys_user where user_name = ? and password = ?", new String[]{username, password}); if(map != null){ user = new User(map.get("id").toString(),map.get("nick_name").toString(),map.get("user_name").toString(),map.get("password").toString()); } //关闭数据库连接 dbUtil.close(); return user; } public List getRoleByUserId(String userId){ //先从缓存中获取 List roles = userRoleMap.get(userId); if(roles != null){ return roles; } //查询数据库 List roleList = null; List> list = dbUtil.find("select r.* from sys_role r join sys_user_role ur on r.id = ur.role_id where ur.user_id = ?", new String[]{userId}); if(list != null){ roleList = new ArrayList<>(list.size()); for (HashMap map : list) { roleList.add(new Role(map.get("id").toString(),map.get("role_name").toString(),map.get("role_menu").toString(),map.get("role_url").toString())); } } //关闭数据库连接 dbUtil.close(); //放到缓存中 userRoleMap.put(userId,roleList); return roleList; } /* 3张基础表 sys_user 系统用户表 id 表id nick_name 昵称 user_name 账号 password 密码 sys_role 系统角色表 id 表id role_name 角色名称 role_menu 角色菜单可视权限(可以不关联菜单,单独做成菜单管理直接与用户关联) role_url 角色URL访问权限 sys_user_role 系统用户-角色关联表 id 表id user_id 用户id role_id 角色id */ public class User{ private String id;//表id private String nickName;//昵称 private String userName;//账号 private String password;//密码 public User(String id, String nickName, String userName, String password) { this.id = id; this.nickName = nickName; this.userName = userName; this.password = password; } public String getId() { return id; } public String getNickName() { return nickName; } public String getUserName() { return userName; } public String getPassword() { return password; } } public class Role{ private String id;//表id private String RoleName;//角色名称 private String RoleMenu;//角色菜单可视权限(可以不关联菜单,单独做成菜单管理直接与用户关联) private String RoleUrl;//角色URL访问权限 public Role(String id, String roleName, String roleMenu, String roleUrl) { this.id = id; RoleName = roleName; RoleMenu = roleMenu; RoleUrl = roleUrl; } public String getId() { return id; } public String getRoleName() { return RoleName; } public String getRoleMenu() { return RoleMenu; } public String getRoleUrl() { return RoleUrl; } } public class UserRole{ private String id;//表id private String UserId;//用户id private String RoleId;//角色id } }
数据库目前用的是mysql,使用时要记得添加驱动依赖 SpringBoot整合 代码
PS:我们自定义DbUtil工具类获取连接操作,SpringBoot项目需要带上时区、字符集参数jdbc:mysql://localhost/jfinal_demo?serverTimezone=GMT%2B8&characterEncoding=utf-8
新建一个springboot项目或在我们的springBoot项目中随便挑一个来测试
首先需要将springboot-exceptionhandler项目中自定义统一异常处理相关代码拷贝过来,方便捕获我们抛出的业务异常
然后新建一个AccessAuthorityFilter拦截器/** * SpringBoot测试鉴权拦截器 */ @WebFilter(filterName = "AccessAuthorityFilter",urlPatterns = {"/**"}) @ServletComponentScan @Component public class AccessAuthorityFilter implements Filter { @Override public void init(FilterConfig filterConfig) { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //请求头 HttpServletRequest request = (HttpServletRequest) servletRequest; SecurityUtil securityUtil = SecurityUtil.getInstance(); //鉴权中心 String auc = securityUtil.auc(request); if("UNAUTHORIZED".equals(auc)){ throw new ServiceException(ErrorEnum.UNAUTHORIZED); } if("FORBIDDEN".equals(auc)){ throw new ServiceException(ErrorEnum.FORBIDDEN); } //执行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
写几个测试接口,包括login登录、logout注销等/** * 测试接口 */ @RestController public class TestController { /** * 简单登录、注销、获取登录用户 */ @GetMapping("/login") public String login(HttpServletRequest request,String username, String password){ SecurityUtil securityUtil = SecurityUtil.getInstance(); SecurityUtil.User user = securityUtil.getUserByUserNameAndPassword(username, password); if(user != null){ securityUtil.setLoginUser(request,user); return "登录成功!"; }else{ return "账号或密码错误..."; } } @GetMapping("/logout") public String logout(HttpServletRequest request){ SecurityUtil securityUtil = SecurityUtil.getInstance(); SecurityUtil.User loginUser = securityUtil.getLoginUser(request); securityUtil.setLoginUser(request,null); return "注销成功!"; } @GetMapping("/getLoginUser") public HashMap getLoginUser(HttpServletRequest request){ SecurityUtil securityUtil = SecurityUtil.getInstance(); SecurityUtil.User loginUser = securityUtil.getLoginUser(request); List loginUserRole = securityUtil.getLoginUserRole(request); HashMap map = new HashMap<>(2); map.put("loginUser",loginUser); map.put("loginUserRole",loginUserRole); return map; } /** * 登录、鉴权测试接口 */ @GetMapping("/sys/xtgl") public String xtgl() { return "系统管理..."; } @GetMapping("/sys/yhgl") public String yhgl() { return "用户管理..."; } @GetMapping("/portal/mhgl") public String mhgl() { return "网站门户管理..."; } @GetMapping("/portal/index") public String portalIndex() { return "网站门户首页..."; } }
效果
未登录时,只有配置在无需登录即可访问的URL才能允许访问
登录后,除了无需权限的URL,还可以访问角色允许访问的URL,注销后恢复登录前状态
SpringBoot项目比较常规大家用的也比较多,代码就不上传了 JFinal整合 代码
创建一个访问权限拦截器AccessAuthorityInterceptorpackage cn.huanzi.qch.interceptor; import cn.huanzi.qch.common.model.ErrorEnum; import cn.huanzi.qch.common.model.ServiceException; import cn.huanzi.qch.util.SecurityUtil; import com.jfinal.aop.Interceptor; import com.jfinal.aop.Invocation; import com.jfinal.log.Log; import javax.servlet.http.HttpServletRequest; /** * 访问权限拦截器 */ public class AccessAuthorityInterceptor implements Interceptor { private static final Log log = Log.getLog(AccessAuthorityInterceptor.class); @Override public void intercept(Invocation invocation) { //请求头 HttpServletRequest request = invocation.getController().getRequest(); SecurityUtil securityUtil = SecurityUtil.getInstance(); //鉴权中心 String auc = securityUtil.auc(request); if("UNAUTHORIZED".equals(auc)){ throw new ServiceException(ErrorEnum.UNAUTHORIZED); } if("FORBIDDEN".equals(auc)){ throw new ServiceException(ErrorEnum.FORBIDDEN); } invocation.invoke(); } }
AppConfig中注册拦截器/** * API 引导式配置 */ public class AppConfig extends JFinalConfig { //省略其他代码... /** * 配置路由 */ public void configRoute(Routes me) { //省略其他代码... // 此处配置 Routes 级别的拦截器,可配置多个 me.addInterceptor(new AccessAuthorityInterceptor()); } //省略其他代码... }
写几个测试接口,包括login登录、logout注销等/** * 用户表 Controller * * 作者:Auto Generator By "huanzi-qch" * 生成日期:2021-07-29 17:32:50 */ @Path(value = "/user",viewPath = "/user") public class UserController extends CommonController { //省略其他代码... /** * 简单登录、注销、获取登录用户 */ @ActionKey("/login") public void login() { String username = get("username"); String password = get("password"); SecurityUtil securityUtil = SecurityUtil.getInstance(); SecurityUtil.User user = securityUtil.getUserByUserNameAndPassword(username, password); if(user != null){ securityUtil.setLoginUser(this.getRequest(),user); renderText("登录成功!"); }else{ renderText("账号或密码错误..."); } } @ActionKey("/logout") public void logout() { SecurityUtil securityUtil = SecurityUtil.getInstance(); SecurityUtil.User loginUser = securityUtil.getLoginUser(this.getRequest()); securityUtil.setLoginUser(this.getRequest(),null); renderText("注销成功!"); } @ActionKey("/getLoginUser") public void getLoginUser() { SecurityUtil securityUtil = SecurityUtil.getInstance(); SecurityUtil.User loginUser = securityUtil.getLoginUser(this.getRequest()); List loginUserRole = securityUtil.getLoginUserRole(this.getRequest()); HashMap map = new HashMap<>(2); map.put("loginUser",loginUser); map.put("loginUserRole",loginUserRole); renderJson(map); } /** * 登录、鉴权测试接口 */ @ActionKey("/sys/xtgl") public void xtgl() { renderText("系统管理..."); } @ActionKey("/sys/yhgl") public void yhgl() { renderText("用户管理..."); } @ActionKey("/portal/mhgl") public void mhgl() { renderText("网站门户管理..."); } @ActionKey("/portal/index") public void portalIndex() { renderText("网站门户首页..."); } } 效果
未登录时,只有配置在无需登录即可访问的URL才能允许访问
登录后,除了无需权限的URL,还可以访问角色允许访问的URL,注销后恢复登录前状态
JFinal项目的整合代码在我的jfinal-demo项目中:不想用Spring全家桶?试试这个国产JFinal框架 后记
一套简单的登录、鉴权工具暂时先记录到这,后续再进行补充版权声明
作者:huanzi-qch
出处:https://www.cnblogs.com/huanzi-qch
若标题中有"转载"字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.
中美印日俄德越南等国2022年GDP增速预计有多少呢?通胀已走向全球,居民消费能力受到较大侵蚀,融资环境收紧可能引发广泛的债务困局,叠加俄乌冲突,疫情频发带来的不确定性等多种因素的交织,让各国在运用财政和货币政策时更加的艰难。国际货币
3000点的市场,我们在没有钱的情况下如何加仓市场一直在3000点附近徘徊不前。眼看着手中的现金再也没有办法继续保持定投。这样的躺平确实太让人难以称心。无论哪个年代的3000点,它的最终结果都会给了我们一个提示这是一个黄金坑的
中概股纷纷离开美国金融市场,到底是好事,还是坏事?2020年底,美国国会通过了外国公司问责法案,要求在美上市的外国公司如果连续三年不能满足其审计要求的,证券将被禁止在美国交易。也就是说,到2023年底,如果中美双方仍不能就审计底稿
人民日报每日摘抄(204)1。功崇惟志,业广惟勤。2。业绩是干出来的,奇迹是干出来的。3。若问何花开不败,英雄创业越千秋。4。岁月为证,山河为凭。5。树高千尺,其根必深江河万里,其源必长。6。一切脱离人民的
杨紫的8帧美照,每帧都是珍藏款1。既然不得不做出选择,那就请面带微笑态度严肃没有所谓的沿袭正道或逐步偏离。就让执念一路冲锋陷阵,因为我们的去向,从来都掌握在自己手中。2。南山的心跳仍在继续,我们的脚步也没有停息
游戏迷盛阳上线!骄阳伴我拍摄进行中,肖战被曝片场打游戏这段时间,相信不少网友都被一款小游戏羊了个羊所吸引。看似简单的玩法,却让无数人折在了第二关。加之该游戏引入的省市排名方式,更让不少玩家欲罢不能,誓要为家乡争口气。而如此热门的游戏,
一款有趣的小偷模拟游戏HELLO大家好,这里是小白的每日一游推荐时间。世上的游戏千千万,有许多好玩的游戏由于缺乏宣传,所以不被广大玩家所熟知。在这里小白每天会为大家推荐一款评价很高但是不太出名的游戏美国
人民日报这6张图,是我们一生的缩影苏轼说人生如逆旅,我亦是行人。其实,我们都是世间的过客,从出生到死亡,不过短短几十年,抛开青涩懵懂的童年,抛开昏昏欲睡的晚年,真正掌握在手中的好时光,就更少了。等到我们老的那一天,
生活那么苦,总是要加点糖,尽管结果可能更苦涩,但总归有点甜怅然回眸,数十载悠悠而过。猛然回头,心路有数人擦肩。冷月夜,杯酒问明月,他朝若得伊人顾,不堕黄泉终不悔。点燃的烟圈一点点围绕在身边变幻成各种各样的形状,却唯独变幻不出你的模样,寂寥
不能没有钱,但钱也不是万能的俗话说得好钱不是万能的,但是没有钱是万万不能的。一句话说明的钱的重要性,也同样说明了有的时候钱也是无能为力的。01任何人在任何时候,都离不开钱。在我们生活中的每一天中,都离不开钱,
人不负时代,时代不负人太阳升起在东方,却在西方落山朋友在人海相识,却在酒席散去。这也是一种自然规律和社交的规矩。世间一切都在运动着,变化着,我们应该遵循自然规律,顺应时代潮流,用发展的眼光看待时间的一切