天天看點

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全局異常捕獲