SpringBoot Security | 三、简单自定义许可和角色

目录

 

一、项目实现

增加数据库表:

加入自定义许可逻辑

二、测试


一、项目实现

增加数据库表:

sql:

DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
  `description` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `url` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
  `pid` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of sys_permission
-- ----------------------------
INSERT INTO `sys_permission` VALUES ('1', 'ROLE_HOME', 'home', '/', null);
INSERT INTO `sys_permission` VALUES ('2', 'ROLE_ADMIN', 'ABel', '/admin', null);
INSERT INTO `sys_permission` VALUES ('4', 'ROLE_USER', 'user', '/getUser', null);

-- ----------------------------
-- Table structure for sys_permission_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission_role`;
CREATE TABLE `sys_permission_role` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `role_id` bigint(20) unsigned NOT NULL,
  `permission_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of sys_permission_role
-- ----------------------------
INSERT INTO `sys_permission_role` VALUES ('1', '1', '1');
INSERT INTO `sys_permission_role` VALUES ('2', '1', '2');
INSERT INTO `sys_permission_role` VALUES ('3', '2', '1');
INSERT INTO `sys_permission_role` VALUES ('4', '1', '4');

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES ('1', 'ROLE_ADMIN');
INSERT INTO `sys_role` VALUES ('2', 'ROLE_USER');

-- ----------------------------
-- Table structure for sys_role_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_user`;
CREATE TABLE `sys_role_user` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `sys_user_id` bigint(20) unsigned NOT NULL,
  `sys_role_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of sys_role_user
-- ----------------------------
INSERT INTO `sys_role_user` VALUES ('1', '1', '1');
INSERT INTO `sys_role_user` VALUES ('2', '2', '2');

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
  `password` varchar(200) COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('1', 'admin', '202cb962ac59075b964b07152d234b70');
INSERT INTO `sys_user` VALUES ('2', 'abel', 'abel');

public class Permission {

    private int id;
    //权限名称
    private String name;

    //权限描述
    private String descritpion;

    //授权链接
    private String url;

..
}
public class SecurityUser implements UserDetails {

    private static final long serialVersionUID=1L;
    private Long id;
    private String username;
    private String password;
    private List<GrantedAuthority> anthorities;

...
}

mapper:

public interface PermissionMapper {

    @Select("select * from sys_permission")
    public List<Permission> findAll();


    @Select("select p.* " +
            "from Sys_User u " +
            "LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id " +
            "LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id " +
            "LEFT JOIN Sys_permission_role spr on spr.role_id=r.id " +
            "LEFT JOIN Sys_permission p on p.id =spr.permission_id " +
            "where u.id=#{userId}")
    public List<Permission> findByAdminUserId(Long userId);
}

public interface SecurityUserMapper {

    //新增用户
    @Insert("insert into sys_user(username,password) value(#{username},#{password})")
    @Options(useGeneratedKeys=true,keyColumn="id",keyProperty="id")
    public void insert(SecurityUser SecurityUser);

    //查找所有用户
    @Select("select * from sys_user")
    public List<SecurityUser> getAll();

    //根据id查找用户
    @Select("select * from sys_user where id=#{id}")
    public SecurityUser getById(int id);

    @Select("select * from sys_user where username=#{username}")
    public SecurityUser getByName(String username);

    //根据id删除用户
    @Delete("delete from sys_user where id=#{id}")
    public boolean deleteById(int id);

}

加入自定义许可逻辑

MySecurityMetadataSource类,继承于FilterInvocationSecurityMetadataSource; 获取路径所需角色
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private PermissionMapper permissionMapper;

    private HashMap<String, Collection<ConfigAttribute>> map =null;

    @PostConstruct
    public void init() {
        map = new HashMap<>();
        Collection<ConfigAttribute> array;
        ConfigAttribute cfg;
        List<Permission> permissions = permissionMapper.findAll();
        for(Permission permission : permissions) {
            array = new ArrayList<>();
            cfg = new SecurityConfig(permission.getName());
            array.add(cfg);
            map.put(permission.getUrl(), array);
        }
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        HttpServletRequest request = ((FilterInvocation) object).getRequest();

        AntPathRequestMatcher matcher;
        for (String resUrl : map.keySet()) {
            log.info("MySecurityMetadataSource resUrl:{} request:{}", resUrl, request.getRequestURI());
            matcher = new AntPathRequestMatcher(resUrl);
            if (matcher.matches(request)) {
//                ConfigAttribute configAttribute = new MyConfigAttribute(request,new MyGrantedAuthority(jurisdiction.getMethod(),jurisdiction.getUrl()));
//                allConfigAttribute.add(configAttribute);
//                return allConfigAttribute;
                return map.get(resUrl);
            }
        }

        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
//        return FilterInvocation.class.isAssignableFrom(clazz);
        return true;
    }
}
MyAccessDecisionManager类,继承于AccessDecisionManager, 用户角色与路径角色是否匹配。
public class MyAccessDecisionManager implements AccessDecisionManager {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
        log.info("MyAccessDecisionManager join");
        if(configAttributes == null || configAttributes.size()==0) {
            return;
        }
//        if(!authentication.isAuthenticated()) {
//            throw new InsufficientAuthenticationException("未登录");
//        }
//        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
//        for(ConfigAttribute attribute : collection){
//            MyConfigAttribute urlConfigAttribute = (MyConfigAttribute)attribute;
//            for(GrantedAuthority authority: authorities){
//                MyGrantedAuthority myGrantedAuthority = (MyGrantedAuthority)authority;
//                if(urlConfigAttribute.getMyGrantedAuthority().equals(myGrantedAuthority))
//                    return;
//            }
//        }
        String needRole;
        for (ConfigAttribute c : configAttributes) {
            needRole = c.getAttribute();
            log.info("MyAccessDecisionManager needRole:{}", needRole);
            for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
                log.info("MyAccessDecisionManager ga:{}", ga.getAuthority());
                if(needRole.trim().equals(ga.getAuthority())) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("无权限");
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}
MyFilterSecurityInterceptor类,过滤器,设置后角色权限逻辑通过过滤器启用
@Component
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private MySecurityMetadataSource mySecurityMetadataSource;

    @Autowired
    private MyAccessDecisionManager myAccessDecisionManager;

    @PostConstruct
    public void setMyAccessDecisionManager() {
        super.setAccessDecisionManager(myAccessDecisionManager);
    }

    @Override
    public Class<?> getSecureObjectClass() {
        return FilterInvocation.class;
    }

    @Override
    public SecurityMetadataSource obtainSecurityMetadataSource() {
        return mySecurityMetadataSource;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FilterInvocation fi = new FilterInvocation(request, response, chain);
        invoke(fi);
    }

    public void invoke(FilterInvocation fi) throws IOException, ServletException {
        logger.info("MyFilterSecurityInterceptor {}", fi.getRequest().getRequestURI());
        InterceptorStatusToken token = super.beforeInvocation(fi);
        try {
            fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
        } finally {
            super.afterInvocation(token, null);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }
}

在SecurityConfig中,配置过滤器,启用逻辑

http.addFilterBefore(urlFilterSecurityInterceptor , FilterSecurityInterceptor.class);

二、测试

  1. 启动
  2. 访问路径 http://localhost:8001/getUser,跳转登陆界面
  3. 输入账户密码  admin/123
  4. 显示getUser接口信息

 

用户注册登陆时逻辑

  • SecurityUserService  获取用户名密码以及用户权限

  • MyPasswordEncoder  加密并匹配密码

  • MyFilterSecurityInterceptor  过滤器,设置后角色权限逻辑通过过滤器启用

  • MySecurityMetadataSource  获取路径所需角色

  • MyAccessDecisionManager  用户角色与路径角色是否匹配

代码传送门

参考:https://www.cnblogs.com/softidea/p/7068149.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值