您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

一套简单的登录、鉴权工具

时间:2021-11-26 10:12:24  来源:博客园  作者:huanzi一qch

前言

  无论是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<HashMap<String,Object>> find(String sql, Object[] params) {
        ArrayList<HashMap<String, Object>> 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<String, Object> 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<String,Object> findOne(String sql, Object[] params){
        ArrayList<HashMap<String, Object>> list = this.find(sql, params);
        return list.size() > 0 ? list.get(0) : null;
    }
    public ArrayList<HashMap<String,Object>> find(String sql) {
        return this.find(sql,null);
    }
    public HashMap<String,Object> 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<String,List<Role>> 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<Role> 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<String, Object> 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<Role> getRoleByUserId(String userId){
        //先从缓存中获取
        List<Role> roles = userRoleMap.get(userId);
        if(roles != null){
            return roles;
        }

        //查询数据库
        List<Role> roleList = null;
        List<HashMap<String, Object>> 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<String, Object> 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<String, Object> getLoginUser(HttpServletRequest request){
        SecurityUtil securityUtil = SecurityUtil.getInstance();
        SecurityUtil.User loginUser = securityUtil.getLoginUser(request);
        List<SecurityUtil.Role> loginUserRole = securityUtil.getLoginUserRole(request);

        HashMap<String, Object> 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整合

  代码

  创建一个访问权限拦截器AccessAuthorityInterceptor

package 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<User,UserServiceImpl> {
    //省略其他代码...

    /**
     * 简单登录、注销、获取登录用户
     */
    @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<SecurityUtil.Role> loginUserRole = securityUtil.getLoginUserRole(this.getRequest());

        HashMap<String, Object> 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

若标题中有“转载”字样,则本文版权归原作者所有。若无转载字样,本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利.



Tags:工具   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
从本质上来讲,PE系统最广泛的用途只是用来安装系统。通过其内置的Ghost软件来调用第三方的GHO系统镜像来完成系统的安装。从表面来看,最终的系统是否纯净、是否安全,与Gho镜像...【详细内容】
2021-12-27  Tags: 工具  点击:(2)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  Tags: 工具  点击:(11)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  Tags: 工具  点击:(9)  评论:(0)  加入收藏
MacBook上有不少像IINA、Downie等强大的神器,有像预览、文档编辑等基础软件,也有一些像快捷指令、Automator以及活动监视器等这样一些效率工具软件。 但是在大部分时候,Mac上自...【详细内容】
2021-12-23  Tags: 工具  点击:(16)  评论:(0)  加入收藏
《开源精选》是我们分享Github、Gitee等开源社区中优质项目的栏目,包括技术、学习、实用与各种有趣的内容。本期推荐的HasorDB 是一个全功能数据库访问工具,提供对象映射、丰...【详细内容】
2021-12-22  Tags: 工具  点击:(5)  评论:(0)  加入收藏
# 1. nps-npc1.1 简介nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发,可支持任何tcp、udp上层协议(访问内网网站、本地支付接口调试、ssh...【详细内容】
2021-12-22  Tags: 工具  点击:(8)  评论:(0)  加入收藏
近几年,国家开始加大对博彩、洗钱的打击力度,对于整个支付行业颁布了一系列新规,严防支付通道被滥用,首当其中的就是对博彩行业的影响,于是一个新的支付方式悄然兴起,就是我们常听...【详细内容】
2021-12-20  Tags: 工具  点击:(9)  评论:(0)  加入收藏
大家好,我是等天黑, 今天介绍一个开源免费的监控工具 Uptime Kuma, 简单实用, 主要用来监控 Web 和网络, 和 Prometheus 不一样的是, 它是轻量的, 基于Node.js 和 Vue 3 开发...【详细内容】
2021-12-16  Tags: 工具  点击:(13)  评论:(0)  加入收藏
引子感谢绿地,18年买的房子现在外墙还没做完,今年是奶爸的第四个租房的年头了,9月份刚刚换了一间大一点的房子。大房子住着倒是舒服些,然而房东配的床却完全不走心,这不前两天大...【详细内容】
2021-12-16  Tags: 工具  点击:(6)  评论:(0)  加入收藏
最近汇总了平时常用到的9个很好的Python工具,它们能极大的提高我们的工作效率,安装它们,然后逐步熟练使用它们。若有用,可以收藏这篇文章。1 Faker生成假数据你若还在为生成名字...【详细内容】
2021-12-14  Tags: 工具  点击:(16)  评论:(0)  加入收藏
▌简易百科推荐
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(1)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(9)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(19)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(23)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(24)  评论:(0)  加入收藏
一个项目的大部分API,测试用例在参数和参数值等信息会有很多相似的地方。我们可以复制API,复制用例来快速生成,然后做细微调整既可以满足我们的测试需求1.复制API:在菜单发布单...【详细内容】
2021-12-14  AutoMeter    Tags:AutoMeter   点击:(20)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条