springboot+spring security+redis实现登录权限管理

笔者负责的电商项目的技术体系是基于SpringBoot,为了实现一套后端能够承载ToB和ToC的业务,需要完善现有的权限管理体系。
在查看Shiro和Spring Security对比后,笔者认为Spring Security更加适合本项目使用,可以总结为以下2点:
1、基于拦截器的权限校验逻辑,可以针对ToB的业务接口来做相关的权限校验,以笔者的项目为例,ToB的接口请求路径以/openshop/api/开头,可以根据接口请求路径配置全局的ToB的拦截器;
2、Spring Security的权限管理模型更简单直观,对权限、角色和用户做了很好的解耦。
以下介绍本项目的实现步骤

一、在项目中添加Spring相关依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>1.5.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.8.RELEASE</version>
        </dependency>

二、使用模板模式定义权限管理拦截器抽象类

public abstract class AbstractAuthenticationInterceptor extends HandlerInterceptorAdapter implements InitializingBean {
     

    @Resource
    private AccessDecisionManager accessDecisionManager;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
     
        //检查是否登录
        String userId = null;
        try {
     
            userId = getUserId();
        }catch (Exception e){
     
            JsonUtil.renderJson(response,403,"{}");
            return false;
        }
        if(StringUtils.isEmpty(userId)){
     
            JsonUtil.renderJson(response,403,"{}");
            return false;
        }
        //检查权限
        Collection<? extends GrantedAuthority> authorities = getAttributes(userId);
        Collection<ConfigAttribute>  configAttributes = getAttributes(request);
        return accessDecisionManager.decide(authorities,configAttributes);
    }

    //获取用户id
    public abstract String getUserId();

    //根据用户id获取用户的角色集合
    public abstract  Collection<? extends GrantedAuthority> getAttributes(String userId);

    //查询请求需要的权限
    public abstract Collection<ConfigAttribute> getAttributes(HttpServletRequest request);

}

三、权限管理拦截器实现类 AuthenticationInterceptor

@Component
public class AuthenticationInterceptor extends AbstractAuthenticationInterceptor {
     

    @Resource
    private SessionManager sessionManager;

    @Resource
    private UserPermissionService customUserService;

    @Override
    public String getUserId() {
     
        return sessionManager.obtainUserId();
    }

    @Override
    public Collection<? extends GrantedAuthority> getAttributes(String s) {
     
        return customUserService.getAuthoritiesById(s);
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(HttpServletRequest request) {
     
        return customUserService.getAttributes(request);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
     

    }
}

四、用户Session信息管理类

集成redis维护用户session信息

@Component
public class SessionManager {
     
    private static final Logger logger = LoggerFactory.getLogger(SessionManager.class);
    @Autowired
    private RedisUtils redisUtils;

    public SessionManager() {
     
    }

    public UserInfoDTO obtainUserInfo() {
     
        UserInfoDTO userInfoDTO = null;

        try {
     
            String token = this.obtainToken();
            logger.info("=======token=========", token);
            if (StringUtils.isEmpty(token)) {
     
                LemonException.throwLemonException(AccessAuthCode.sessionExpired.getCode(), AccessAuthCode.sessionExpired.getDesc());
            }

            userInfoDTO = (UserInfoDTO)this.redisUtils.obtain(this.obtainToken(), UserInfoDTO.class);
        } catch (Exception var3) {
     
            logger.error("obtainUserInfo ex:", var3);
        }

        if (null == userInfoDTO) {
     
            LemonException.throwLemonException(AccessAuthCode.sessionExpired.getCode(), AccessAuthCode.sessionExpired.getDesc());
        }

        return userInfoDTO;
    }

    public String obtainUserId() {
     
        return this.obtainUserInfo().getUserId();
    }

    public String obtainToken() {
     
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader("token");
        return token;
    }

    public UserInfoDTO createSession(UserInfoDTO userInfoDTO, long expired) {
     
        String token = UUIDUtil.obtainUUID("token.");
        userInfoDTO.setToken(token);
        if (expired == 0L) {
     
            this.redisUtils.put(token, userInfoDTO);
        } else {
     
            this.redisUtils.put(token, userInfoDTO, expired);
        }

        return userInfoDTO;
    }

    public void destroySession() {
     
        String token = this.obtainToken();
        if (StringUtils.isNotBlank(token)) {
     
            this.redisUtils.remove(token);
        }

    }
}

五、用户权限管理service

@Service
public class UserPermissionService {
     

    @Resource
    private SysUserDao userDao;
    @Resource
    private SysPermissionDao permissionDao;


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

    /**
     * 加载资源,初始化资源变量
     */
    public void loadResourceDefine(){
     
        map = new HashMap<>();
        Collection<ConfigAttribute> array;
        ConfigAttribute cfg;
        List<SysPermission> permissions = permissionDao.findAll();
        for(SysPermission permission : permissions) {
     
            array = new ArrayList<>();
            cfg = new SecurityConfig(permission.getName());
            array.add(cfg);
            map.put(permission.getUrl(), array);
        }

    }

/*
*
 * @Author zhangs
 * @Description 获取用户权限列表
 * @Date 18:56 2019/11/11
 **/
    public List<GrantedAuthority> getAuthoritiesById(String userId) {
     
        SysUserRspDTO user = userDao.findById(userId);
        if (user != null) {
     
            List<SysPermission> permissions = permissionDao.findByAdminUserId(user.getUserId());
            List<GrantedAuthority> grantedAuthorities = new ArrayList <>();
            for (SysPermission permission : permissions) {
     
                if (permission != null && permission.getName()!=null) {
     

                    GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
                    grantedAuthorities.add(grantedAuthority);
                }
            }
            return grantedAuthorities;
        }
        return null;
    }

    /*
    *
     * @Author zhangs
     * @Description 获取当前请求所需权限 
     * @Date 18:57 2019/11/11
     **/
    public Collection<ConfigAttribute> getAttributes(HttpServletRequest request) throws IllegalArgumentException {
     
        if(map !=null) map.clear();
        loadResourceDefine();
        AntPathRequestMatcher matcher;
        String resUrl;
        for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
     
            resUrl = iter.next();
            matcher = new AntPathRequestMatcher(resUrl);
            if(matcher.matches(request)) {
     
                return map.get(resUrl);
            }
        }
        return null;
    }

}

六、权限校验类 AccessDecisionManager

通过查看authorities中的权限列表是否含有configAttributes中所需的权限,判断用户是否具有请求当前资源或者执行当前操作的权限。

@Service
public class AccessDecisionManager {
     

    public boolean decide(Collection<? extends GrantedAuthority> authorities, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
     

        if(null== configAttributes || configAttributes.size() <=0) {
     
            return true;
        }
        ConfigAttribute c;
        String needRole;
        for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
     
            c = iter.next();
            needRole = c.getAttribute();
            for(GrantedAuthority ga : authorities) {
     
                if(needRole.trim().equals(ga.getAuthority())) {
     
                    return true;
                }
            }
        }
        return false;
    }

}

七、配置拦截规则

@Configuration
public class WebAppConfigurer extends WebMvcConfigurerAdapter {
     
    @Resource
    private AbstractAuthenticationInterceptor authenticationInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
     
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用户排除拦截
        //对来自/openshop/api/** 这个链接来的请求进行拦截
        registry.addInterceptor(authenticationInterceptor).addPathPatterns("/openshop/api/**");
        super.addInterceptors(registry);
    }

}

八 相关表说明

用户表 sys_user

CREATE TABLE `sys_user` (
  `user_id` varchar(64) NOT NULL COMMENT '用户ID',
  `username` varchar(255) DEFAULT NULL COMMENT '登录账号',
  `first_login` datetime(6) NOT NULL COMMENT '首次登录时间',
  `last_login` datetime(6) NOT NULL COMMENT '上次登录时间',
  `pay_pwd` varchar(100) DEFAULT NULL COMMENT '支付密码',
  `chant_id` varchar(64) NOT NULL DEFAULT '-1' COMMENT '关联商户id',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `modify_time` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

角色表 sys_role

CREATE TABLE `sys_role` (
  `role_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `modify_time` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

用户角色关联表 sys_role_user

CREATE TABLE `sys_role_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sys_user_id` varchar(64) DEFAULT NULL,
  `sys_role_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

权限表 sys_premission

CREATE TABLE `sys_permission` (
  `permission_id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL COMMENT '权限名称',
  `description` varchar(255) DEFAULT NULL COMMENT '权限描述',
  `url` varchar(255) DEFAULT NULL COMMENT '资源url',
  `check_pwd` int(2) NOT NULL DEFAULT '1' COMMENT '是否检查支付密码:0不需要 1 需要',
  `check_sms` int(2) NOT NULL DEFAULT '1' COMMENT '是否校验短信验证码:0不需要 1 需要',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `modify_time` datetime DEFAULT NULL COMMENT '修改时间',
  PRIMARY KEY (`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

角色权限关联表 sys_permission_role

CREATE TABLE `sys_permission_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_id` int(11) DEFAULT NULL,
  `permission_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

你可能感兴趣的:(权限管理,spring,security)