1. 程式人生 > >SpringBoot整合Shiro (二)

SpringBoot整合Shiro (二)

mark alc depend sco repo 服務 框架 filter des

Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼學和會話管理。相比較Spring Security,shiro有小巧、簡單、易上手等的優點。所以很多框架都在使用shiro。

Shiro包含了三個核心組件:Subject, SecurityManager 和 Realms。

  • Subject 代表了當前用戶的安全操作。
  • SecurityManager 則管理所有用戶的安全操作。它是Shiro框架的核心,典型的Facade模式,Shiro通過SecurityManager來管理內部組件實例,並通過它來提供安全管理的各種服務。
  • Realm 充當了Shiro與應用安全數據間的“橋梁”或者“連接器”。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其權限信息。

下面通過示例來演示SpringBoot如何來整合Shiro

1、創建項目ShiroDemo
技術分享圖片

2、配置POM,添加SpringBoot以及Shiro依賴

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

  <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        </dependency>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.1.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.25</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>0.2.23</version>
    </dependency>
    <!-- shiro權限控制框架 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
  </dependencies>

3、編寫MyShiroRealm類,實現AuthorizingRealm接口

public class MyShiroRealm extends AuthorizingRealm {

    /**
     * 授權用戶權限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
            PrincipalCollection principals) {
        //獲取用戶
        User user = (User)SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info 
= new SimpleAuthorizationInfo(); //獲取用戶角色 Set<String> roleSet = new HashSet<String>(); roleSet.add("100002"); info.setRoles(roleSet); //獲取用戶權限 Set<String> permissionSet = new HashSet<String>(); permissionSet.add("權限添加"); permissionSet.add("權限刪除"); info.setStringPermissions(permissionSet); return info; } /** * 驗證用戶身份 */ @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String username = token.getUsername(); String password = String.valueOf(token.getPassword()); Map<String, Object> map = new HashMap<String, Object>(); map.put("nickname", username); //密碼進行加密處理 明文為 password+name String paw = password+username; String pawDES = MyDES.encryptBasedDes(paw); map.put("pswd", pawDES); User user = new User(); user.setId("112222"); user.setUsername(username); user.setPassword(pawDES); return new SimpleAuthenticationInfo(user, password, getName()); } }

4、實現ShiroConfiguration

@Configuration
public class ShiroConfiguration {

    /**
     * ShiroFilterFactoryBean 處理攔截資源文件問題。
     * 註意:單獨一個ShiroFilterFactoryBean配置是或報錯的,以為在
     * 初始化ShiroFilterFactoryBean的時候需要註入:SecurityManager
     *
     * Filter Chain定義說明 1、一個URL可以配置多個Filter,使用逗號分隔 2、當設置多個過濾器時,全部驗證通過,才視為通過
     * 3、部分過濾器可指定參數,如perms,roles
     *
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必須設置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登錄成功後要跳轉的鏈接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        // 未授權界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        //自定義攔截器
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        //限制同一帳號同時在線的個數。
        //filtersMap.put("kickout", kickoutSessionControlFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);

        // 權限控制map.
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        // 配置不會被攔截的鏈接 順序判斷
        // 配置退出過濾器,其中的具體的退出代碼Shiro已經替我們實現了
        // 從數據庫獲取動態的權限
        // filterChainDefinitionMap.put("/add", "perms[權限添加]");
        // <!-- 過濾鏈定義,從上向下順序執行,一般將 /**放在最為下邊 -->:這是一個坑呢,一不小心代碼就不好使了;
        // <!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問-->
        //logout這個攔截器是shiro已經實現好了的。
        // 從數據庫獲取
        /*List<SysPermissionInit> list = sysPermissionInitService.selectAll();

        for (SysPermissionInit sysPermissionInit : list) {
            filterChainDefinitionMap.put(sysPermissionInit.getUrl(),
                    sysPermissionInit.getPermissionInit());
        }*/

        shiroFilterFactoryBean
                .setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 設置realm.
        securityManager.setRealm(myShiroRealm());
        // 自定義緩存實現 使用redis
        //securityManager.setCacheManager(cacheManager());
        // 自定義session管理 使用redis
        //securityManager.setSessionManager(sessionManager());
        //註入記住我管理器;
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    public MyShiroRealm myShiroRealm(){
        return new MyShiroRealm();
    }

    /**
     * cookie對象;
     * @return
     */
    public SimpleCookie rememberMeCookie(){
       //這個參數是cookie的名稱,對應前端的checkbox的name = rememberMe
       SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
       //<!-- 記住我cookie生效時間30天 ,單位秒;-->
       simpleCookie.setMaxAge(2592000);
       return simpleCookie;
    }

    /**
     * cookie管理對象;記住我功能
     * @return
     */
    public CookieRememberMeManager rememberMeManager(){
       CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
       cookieRememberMeManager.setCookie(rememberMeCookie());
       //rememberMe cookie加密的密鑰 建議每個項目都不一樣 默認AES算法 密鑰長度(128 256 512 位)
       cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));
       return cookieRememberMeManager;
    }

}

5、編寫LoginController類測試Shiro

@RestController
public class LoginController {

    @RequestMapping(value="/login",method=RequestMethod.POST)
    public String login(String username, String password,String vcode,Boolean rememberMe){
        System.out.println(username);
        UsernamePasswordToken token = new UsernamePasswordToken(username, password,rememberMe);
        SecurityUtils.getSubject().login(token);

        return "loginSuccess";
    }

    @RequestMapping(value="/index",method=RequestMethod.GET)
    public String home(){
        Subject subject = SecurityUtils.getSubject();
        User principal = (User)subject.getPrincipal();

        return "Home";
    }

}

  • 在postman中訪問http://127.0.0.1:8080/login,Body中攜帶參數以及值

技術分享圖片

  • 訪問http://127.0.0.1:8080/index,從Subject中獲取登錄後的用戶信息

技術分享圖片

SpringBoot整合Shiro (二)