shiro使用

shiro

一、shiro是什么?

 Shiro是Apache下的一個開源項目改基。shiro屬于輕量級框架霉翔,相對于SpringSecurity簡單的多,也沒有SpringSecurity那么復(fù)雜 柒凉。

二族阅、主要功能

shiro主要有三大功能模塊:

1. Subject:主體,一般指用戶膝捞。
2. SecurityManager:安全管理器坦刀,管理所有Subject,可以配合內(nèi)部安全組件绑警。(類似于SpringMVC中的DispatcherServlet)
3. Realms:用于進行權(quán)限信息的驗證端礼,一般需要自己實現(xiàn)允跑。

細分功能

1. Authentication:身份認證/登錄(賬號密碼驗證)欲鹏。
2. Authorization:授權(quán)挂洛,即角色或者權(quán)限驗證吏廉。
3. Session Manager:會話管理蕊温,用戶登錄后的session相關(guān)管理跛蛋。
4. Cryptography:加密蝌麸,密碼加密等。
5. Web Support:Web支持咕村,集成Web環(huán)境场钉。
6. Caching:緩存,用戶信息懈涛、角色逛万、權(quán)限等緩存到如redis等緩存中。
7. Concurrency:多線程并發(fā)驗證批钠,在一個線程中開啟另一個線程宇植,可以把權(quán)限自動傳播過去。
8. Testing:測試支持埋心;
9. Run As:允許一個用戶假裝為另一個用戶(如果他們允許)的身份進行訪問指郁。
10. Remember Me:記住我,登錄后拷呆,下次再來的話不用登錄了

三闲坎、具體實現(xiàn)

1、項目目錄

1604471130107.png

pom.xml依賴文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>shiro_demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <spring.shiro.version>1.6.0</spring.shiro.version>
    </properties>

    <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>
        <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${spring.shiro.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--頁面模板依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!--熱部署依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Permissions權(quán)限實體類

package org.example.bean;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Permissions {
    private String id;
    private String permissionsName;
}

Role角色實體

package org.example.bean;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Set;

@Data
@AllArgsConstructor
public class Role {

    private String id;
    private String roleName;
    /**
     * 角色對應(yīng)權(quán)限集合
     */
    private Set<Permissions> permissions;
}

User實體

package org.example.bean;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.Set;

@Data
@AllArgsConstructor
public class User {

    private String id;
    private String userName;
    private String password;

    private Set<Role> roles;
}

業(yè)務(wù)層茬斧,模擬數(shù)據(jù)庫

package org.example.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.example.bean.Permissions;
import org.example.bean.Role;
import org.example.bean.User;
import org.example.service.LoginService;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
    @Override
    public User getUserByName(String getMapByName) {
        return getMapByName(getMapByName);
    }

    /**
     * 模擬數(shù)據(jù)庫查詢
     *
     * @param userName 用戶名
     * @return User
     */
    private User getMapByName(String userName) {
        Permissions permissions1 = new Permissions("1", "query");
        Permissions permissions2 = new Permissions("2", "add");
        Set<Permissions> permissionsSet = new HashSet<>(2);
        permissionsSet.add(permissions1);
        permissionsSet.add(permissions2);
        Role role = new Role("1", "admin", permissionsSet);
        Set<Role> roleSet = new HashSet<>();
        roleSet.add(role);
        User user = new User("1", "wsl", "123456", roleSet);
        Map<String, User> map = new HashMap<>(1);
        map.put(user.getUserName(), user);

        Set<Permissions> permissionsSet1 = new HashSet<>(2);
        permissionsSet1.add(permissions1);
        Role role1 = new Role("2", "user", permissionsSet1);
        Set<Role> roleSet1 = new HashSet<>();
        roleSet1.add(role1);
        User user1 = new User("2", "zhangsan", "123456", roleSet1);
        map.put(user1.getUserName(), user1);
        return map.get(userName);
    }
}

CustomRealm用戶權(quán)限配置類

package org.example.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.example.bean.User;
import org.example.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

/**
 * 權(quán)限控制以及權(quán)限認證
 *
 */
public class CustomRealm extends AuthorizingRealm {
    @Autowired
    private LoginService loginService;

    /**
     * 權(quán)限配置類
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //獲取當(dāng)前登錄用戶名
        String userName = principalCollection.getPrimaryPrincipal().toString();
        User user = loginService.getUserByName(userName);

        //添加角色和權(quán)限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        user.getRoles().forEach(role -> {
            simpleAuthorizationInfo.addRole(role.getRoleName());
            role.getPermissions().forEach(permission -> simpleAuthorizationInfo.addStringPermission(permission.getPermissionsName()));
        });
        return simpleAuthorizationInfo;

    }

    /**
     * 權(quán)限認證類
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        Object username = authenticationToken.getPrincipal();
        if (StringUtils.isEmpty(username)) {
            return null;
        }
        //獲取用戶信息
        String name = username.toString();
        User user = loginService.getUserByName(name);
        if (user == null) {
            //這里返回后會報出對應(yīng)異常
            return null;
        } else {
            //這里驗證authenticationToken和simpleAuthenticationInfo的信息
            return new SimpleAuthenticationInfo(name, user.getPassword(), getName());
        }
    }
}

shiro配置類

package org.example.config;

import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.example.shiro.CustomRealm;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * shiro具體配置類
 */
@Configuration
public class ShiroConfig {


    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    /**
     * 將自己的驗證方式加入容器
     */
    @Bean
    public CustomRealm myShiroRealm() {
        return new CustomRealm();
    }

    /**
     * 權(quán)限管理腰懂,配置主要是Realm的管理認證
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    /**
     * Filter工廠,設(shè)置對應(yīng)的過濾條件和跳轉(zhuǎn)條件
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new HashMap<>();
        //登出
        map.put("/logout", "logout");
        //對所有用戶認證
        map.put("/**", "authc");
        //登錄
        shiroFilterFactoryBean.setLoginUrl("/login");
        //首頁
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //錯誤頁面项秉,認證不通過跳轉(zhuǎn)
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }


    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

ExceptionHandler統(tǒng)一異常處理類

package org.example.handler;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice
@Slf4j
public class MyExceptionHandler {

    @ExceptionHandler
    @ResponseBody
    public String ErrorHandler(AuthorizationException e) {
        log.error("沒有通過權(quán)限驗證绣溜!", e);
        return "沒有通過權(quán)限驗證!";
    }
}

controller

package org.example.controller;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.example.bean.User;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Slf4j
public class UserController {

    @GetMapping("/login")
    public String login(User user) {
        if (StringUtils.isEmpty(user.getUserName()) || StringUtils.isEmpty(user.getPassword())) {
            return "請輸入用戶名和密碼伙狐!";
        }
        //用戶認證信息
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
                user.getUserName(),
                user.getPassword()
        );
        try {
            //進行驗證涮毫,這里可以捕獲異常,然后返回對應(yīng)信息
            subject.login(usernamePasswordToken);
        } catch (UnknownAccountException e) {
            log.error("用戶名不存在贷屎!", e);
            return "用戶名不存在罢防!";
        } catch (AuthenticationException e) {
            log.error("賬號或密碼錯誤!", e);
            return "賬號或密碼錯誤唉侄!";
        } catch (AuthorizationException e) {
            log.error("沒有權(quán)限咒吐!", e);
            return "沒有權(quán)限";
        }
        return "login success";
    }

    @RequiresRoles("admin")
    @GetMapping("/admin")
    public String admin() {
        return "admin success!";
    }

    @RequiresPermissions("query")
    @GetMapping("/index")
    public String index() {
        return "index success!";
    }

    @RequiresPermissions("add")
    @GetMapping("/add")
    public String add() {
        return "add success!";
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市属划,隨后出現(xiàn)的幾起案子恬叹,更是在濱河造成了極大的恐慌,老刑警劉巖同眯,帶你破解...
    沈念sama閱讀 212,332評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绽昼,死亡現(xiàn)場離奇詭異,居然都是意外死亡须蜗,警方通過查閱死者的電腦和手機硅确,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,508評論 3 385
  • 文/潘曉璐 我一進店門目溉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人菱农,你說我怎么就攤上這事缭付。” “怎么了循未?”我有些...
    開封第一講書人閱讀 157,812評論 0 348
  • 文/不壞的土叔 我叫張陵陷猫,是天一觀的道長。 經(jīng)常有香客問我的妖,道長绣檬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,607評論 1 284
  • 正文 為了忘掉前任羔味,我火速辦了婚禮河咽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赋元。我一直安慰自己忘蟹,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,728評論 6 386
  • 文/花漫 我一把揭開白布搁凸。 她就那樣靜靜地躺著媚值,像睡著了一般。 火紅的嫁衣襯著肌膚如雪护糖。 梳的紋絲不亂的頭發(fā)上褥芒,一...
    開封第一講書人閱讀 49,919評論 1 290
  • 那天,我揣著相機與錄音嫡良,去河邊找鬼锰扶。 笑死,一個胖子當(dāng)著我的面吹牛寝受,可吹牛的內(nèi)容都是我干的坷牛。 我是一名探鬼主播,決...
    沈念sama閱讀 39,071評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼很澄,長吁一口氣:“原來是場噩夢啊……” “哼京闰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起甩苛,我...
    開封第一講書人閱讀 37,802評論 0 268
  • 序言:老撾萬榮一對情侶失蹤蹂楣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后讯蒲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊土,經(jīng)...
    沈念sama閱讀 44,256評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,576評論 2 327
  • 正文 我和宋清朗相戀三年墨林,在試婚紗的時候發(fā)現(xiàn)自己被綠了施戴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片反浓。...
    茶點故事閱讀 38,712評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡萌丈,死狀恐怖赞哗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辆雾,我是刑警寧澤肪笋,帶...
    沈念sama閱讀 34,389評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站度迂,受9級特大地震影響藤乙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜惭墓,卻給世界環(huán)境...
    茶點故事閱讀 40,032評論 3 316
  • 文/蒙蒙 一坛梁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腊凶,春花似錦划咐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至风瘦,卻和暖如春队魏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背万搔。 一陣腳步聲響...
    開封第一講書人閱讀 32,026評論 1 266
  • 我被黑心中介騙來泰國打工胡桨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瞬雹。 一個月前我還...
    沈念sama閱讀 46,473評論 2 360
  • 正文 我出身青樓昧谊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親挖炬。 傳聞我的和親對象是個殘疾皇子揽浙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,606評論 2 350

推薦閱讀更多精彩內(nèi)容

  • shiro概述 shiro是一個鑒權(quán)框架,鑒(Authentication)是指用戶登錄驗證意敛,權(quán)(Authoriz...
    多關(guān)心老人閱讀 2,425評論 0 1
  • Apache Shiro是Java的一個安全框架馅巷。相比于Spring Security,功能沒那么強大草姻,但是簡單許...
    晏子小七閱讀 668評論 0 1
  • 一钓猬、架構(gòu) Shiro的應(yīng)用不依賴任何容器。下面以用戶登錄為例: 1撩独、使用用戶的登錄信息創(chuàng)建令牌 UsernameP...
    碼超閱讀 322評論 0 0
  • 1. 前言 最近項目中使用到了shiro作為用戶身份驗證以及訪問權(quán)限控制的安全框架敞曹,本文主要簡單介紹一下使用過程账月。...
    aaron1993閱讀 871評論 0 4
  • 前言 相比有做過企業(yè)級開發(fā)的童鞋應(yīng)該都有做過權(quán)限安全之類的功能吧,最先開始我采用的是建用戶表,角色表,權(quán)限表澳迫,之后...
    crossoverJie閱讀 40,983評論 31 179