天天看点

springboot+shiro+vue实现权限管理一 功能简介:二 开始接入:1 数据库设计

springboot+shiro+vue实现权限管理

  • 一 功能简介:
    • 1 介绍:
  • 二 开始接入:
  • 1 数据库设计
    • 2 导入依赖
    • 3 ShiroConfiguration : 设置拦截
    • 4 MyShiroRealm: 用户权限认证
    • 5 LoginService: 用户登录/退出
    • 6 权限使用
    • 7 权限permission编码

一 功能简介:

1 介绍:

Apache Shiro是Java的一个安全框架。对比另一个安全框架Spring Sercurity,它更简单和灵活。 Shiro可以帮助我们完成:认证、授权、加密、会话管理、Web集成、缓存等 2 shiro架构: 对于一个好的框架,从外部看来应该具有非常简单易于使用的API,且API契约明确;从内部来看的话,其应该有一个可扩展的架构,即非常容易插入用户自定义实现,因为任何框架都不能满足所有需求。

二 开始接入:

1 数据库设计

manager:role 关系 n:n

role:permission 关系 n:n

springboot+shiro+vue实现权限管理一 功能简介:二 开始接入:1 数据库设计

2 导入依赖

<dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.0</version>
</dependency>
           

3 ShiroConfiguration : 设置拦截

private String APP = "";  //项目前缀 - 过滤拦截的时候使用

/**
 * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
 * 为了可以使用@RequiresPermissions标签
 * 必须放在最前面
 *
 * @return
 */
@Bean
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
    DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    advisorAutoProxyCreator.setProxyTargetClass(true);
    return advisorAutoProxyCreator;
}

//加入注解的使用,不加入这个注解不生效
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
    authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
    return authorizationAttributeSourceAdvisor;
}


//将自己的验证方式加入容器
@Bean
public MyShiroRealm myShiroRealm() {
    MyShiroRealm myShiroRealm = new MyShiroRealm();
    return myShiroRealm;
}


//权限管理,配置主要是Realm的管理认证
@Bean
public SecurityManager securityManager() {
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    securityManager.setRealm(myShiroRealm());
    return securityManager;
}

//Filter工厂,设置对应的过滤条件和跳转条件
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    Map<String, String> map = new HashMap<String, String>();
    /**
     * 基于DefaultFilter
     anon:所有url都都可以匿名访问;
     authc: 需要认证才能进行访问;
     user:配置记住我或认证通过可以访问;
     */

    //登出
    map.put(APP+ "/logout", "logout");
    //对所有用户认证

    //不拦截
    map.put(APP+ "/index.html", "anon");
    map.put(APP+ "/v1/login/**", "anon");

    //拦截
    map.put(APP+ "/page/intercept/index.html", "authc");
    map.put(APP+ "/page/intercept/**", "authc");

    //权限放行
    map.put(APP+ "/page/intercept/dog3.jpg", "perms[permission:operlog_read]");

    map.put(APP+ "/swagger-ui.html", "perms[permission:permission_write]");

    //登录
    shiroFilterFactoryBean.setLoginUrl(APP+ "/page/login.html");    //拦截后跳转到此页面

    //首页,登录之后跳转
    shiroFilterFactoryBean.setSuccessUrl(APP+ "/page/intercept/index.html");  // 登陆成功后跳转的页面

    //错误页面,认证不通过跳转
    shiroFilterFactoryBean.setUnauthorizedUrl(APP+ "/page/error.html");   //找不到的页面指定跳转
    shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
    return shiroFilterFactoryBean;
    }
    
  }
           

4 MyShiroRealm: 用户权限认证

/**
 * Created by zhiji on 2018/10/25.
 * 进行权限信息处理
 */
public class MyShiroRealm extends AuthorizingRealm {


    // 用于用户查询
    @Autowired
    private ManagerService managerService;

    /**
     * 1 用户访问URL的时候,查询用户权限,并绑定session
     *
     * @param authenticationToken
     * @return 用户信息
     * @throws AuthenticationException 捕获异常,用户是否登陆成功
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        long start = System.currentTimeMillis();

        //加这一步的目的是在Post请求的时候会先进认证,然后在到请求
        if (authenticationToken.getPrincipal() == null) {
            return null;
        }
        //获取用户信息
        String account = authenticationToken.getPrincipal().toString();
        ShiroManagerGetOutDTO shiroManagerGetInDTO = managerService.selectByAccount(account);

        if (shiroManagerGetInDTO == null) {
            //这里返回后会报出对应异常
            return null;
        } else {
            //这里验证authenticationToken和simpleAuthenticationInfo的信息
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(account, shiroManagerGetInDTO.getPassword().toString(), getName());

            long end = System.currentTimeMillis();

            System.out.println(MyShiroRealm.class + " doGetAuthenticationInfo 登录认证 ---------- 总耗时 " + (end - start) + "ms");

            return simpleAuthenticationInfo;
        }
    }

    /**
     * 2 用户登陆的时候,数据库查询用户信息
     * 增加角色
     *
     * @param principalCollection 传递过来的用户信息
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        long start = System.currentTimeMillis();

        //1 获取登录用户名
        String account = (String) principalCollection.getPrimaryPrincipal();

        //2 查询用户名称
        ShiroManagerGetOutDTO manager = managerService.selectByAccount(account);

        if (StringUtils.isEmpty(manager))
            return null;

        //3 添加角色和权限
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        ShiroRoleGetOutDTO role = manager.getShiroRoleGetInDTO();
        if (StringUtils.isEmpty(role))
            return null;

        authorizationInfo.addRole(role.getName());  // 给用户添加角色

        List<ShiroPermissionGetOutDTO> permissions = role.getShiroPermissionGetInDTOList();
        if (StringUtils.isEmpty(permissions) || permissions.size() <= 0)
            return null;

        for (ShiroPermissionGetOutDTO permission : permissions) {
            authorizationInfo.addStringPermission(permission.getPermission());  // 添加用户的权限
        }

        long end = System.currentTimeMillis();

        System.out.println(MyShiroRealm.class + " doGetAuthorizationInfo ---------- 总耗时 " + (end - start) + "ms");

        return authorizationInfo;
    }

    /**
     * 清除所有用户授权信息缓存.
     */
    public void clearCachedAuthorizationInfo(String principal) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName());
        clearCachedAuthorizationInfo(principals);
    }

    /**
     * @return void    返回类型
     * @Title: clearAuthz
     * @Description: TODO 清楚缓存的授权信息
     */
    public void clearAuthz() {
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }


}

           

5 LoginService: 用户登录/退出

public void login(ShiroLoginInDTO manager) {

        ShiroLoginInOutDTO shiroLoginInOutInDTO = new ShiroLoginInOutDTO();

        //添加用户认证信息
        Subject subject = SecurityUtils.getSubject();

        String account = manager.getAccount();
        String password = AppMD5Util.MD5Repeated20(manager.getPassword());   //密码统一使用MD5加密
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(manager.getAccount(), password);
        subject.login(usernamePasswordToken);
        subject.getSession().setTimeout(properties.getPermissionSessionTimeout());   //用户有效登录时长: 1 hours

    }

    public void logout() {

        Subject subject = SecurityUtils.getSubject();

        subject.logout();   //用户退出
        subject.getSession().setTimeout(0);

    }
           

6 权限使用

在controller层加入相应的标签即可

@RequiresPermissions(value = {“permission:app_read”, “permission:app_write”},logical = Logical.OR )

@RequiresRoles(“admin”)

springboot+shiro+vue实现权限管理一 功能简介:二 开始接入:1 数据库设计

7 权限permission编码

0:无
            1:只读 read
            2:读写 write
            
 模块码	名称 编码 编码字符串
 10 	模块一
             100 无权限
             101 permission:permission_read
             102 permission:permission_write
 11 	模块二    
             110 无权限
             111 permission:upload_read
             112 permission:upload_write
 12 	模块三
            120 无权限
            121 permission:publicity_read
            122 permission:publicity_write
           

代码待完善,持续更新。。。

1 将用户token存储到redis中、可以多节点部署

2 自定义token生成规则

3 shiro全局异常捕获