權限框架——shiro的使用看這篇就夠了

關於shiro的學習推薦官網:

在這裏插入圖片描述
鏈接地址: http://shiro.apache.org/

   前言:

     Shiro 是 Java 的一個安全框架。目前,使用 Apache Shiro 的人越來越多,因爲它相當簡單,對比 SpringSecurity,可能沒有 Spring Security 做的功能強大,但是在實際工作時我們可能並不需要那麼複雜的東西,所以使用小而簡單的Shiro 就足夠了。

一、ACL和RBAC

  • ACL: Access Control List
    訪問控制列表 以前盛行的一種權限設計,它的核心在於用戶直接和權限掛鉤
    優點:簡單易用,開發便捷 缺點:用戶和權限直接掛鉤,導致在授予時的複雜性,比較分散,不便於管理 例子:常見的文件系統權限設計, 直接給用戶加權限
  • RBAC: Role Based Access Control
    基於角色的訪問控制系統。權限與角色相關聯,用戶通過成爲適當角色的成員而得到這些角色的權限
    優點:簡化了用戶與權限的管理,通過對用戶進行分類,使得角色與權限關聯起來 缺點:開發對比ACL相對複雜
    例子:基於RBAC模型的權限驗證框架與應用 Apache Shiro、spring Security BAT企業
    ACL,一般是對報表系統,阿里的ODPS

二、shiro中的一些基礎概念和專業名詞(重要)

1、基礎概念:

什麼是身份認證?
Authentication,身份證認證,一般就是登錄

什麼是授權?
Authorization,給用戶分配角色或者訪問某些資源的權限

什麼是會話管理?
Session Management, 用戶的會話管理員,多數情況下是web session

什麼是加密?
Cryptography, 數據加解密,比如密碼加解密等

什麼是主體(subject)?
主體,可以看到主體可以是任何可以與應用交互的“用戶”;

2、shiro實現原理流程圖解:

在這裏插入圖片描述
在這個流程裏面,我們可以看到API 核心就是 Subject,其中各個部分的解釋與作用——

  • Subject:主體,代表了當前 “用戶”,這個用戶不一定是一個具體的人,與當前應用交互的任何東西都是Subject,如網絡爬蟲,機器人等;即一個抽象概念;所有Subject 都綁定到SecurityManager,與 Subject 的所有交互都會委託給 SecurityManager;可以把Subject 認爲是一個門面;SecurityManager纔是實際的執行者;

  • SecurityManager:安全管理器;即所有與安全有關的操作都會與 SecurityManager 交互;且它管理着所有Subject;可以看出它是 Shiro 的核心,它負責與後邊介紹的其他組件進行交互,如果學習過SpringMVC,你可以把它看成DispatcherServlet 前端控制器;

  • Realm:域,Shiro 從 Realm 獲取安全數據(如用戶、角色、權限),就是說 SecurityManager
    要驗證用戶身份,那麼它需要從 Realm 獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從 Realm 得到用戶相應的角色 /權限進行驗證用戶是否能進行操作;可以把 Realm 看成 DataSource,即安全數據源。

如果我們寫一個最簡單的Shiro應用,那麼大概流程應該是——

應用代碼通過 Subject 來進行認證和授權,而 Subject 又委託給 SecurityManager;我們需要給 Shiro 的 SecurityManager 注入 Realm,從而讓 SecurityManager 能得到合法的用戶及其權限進行判斷。

3、架構圖;

在這裏插入圖片描述

4、框架專業名詞解讀

Subject
我們把用戶或者程序稱爲主體(如用戶,第三方服務,cron作業),主體去訪問系統或者資源

SecurityManager
安全管理器,Subject的認證和授權都要在安全管理器下進行

Authenticator
認證器,主要負責Subject的認證

Cache Manager
緩存管理器,比如認證或授權信息,通過緩存進行管理,提高性能

Session Manager
會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通 JavaSE 環境的,也可以是如 Web 環境的;

Realm
數據域,Shiro和安全數據的連接器,好比jdbc連接數據庫; 通過realm獲取認證授權相關信息

Authorizer
授權器,主要負責Subject的授權, 控制subject擁有的角色或者權限

Cryptography
加解密,Shiro的包含易於使用和理解的數據加解密方法,簡化了很多複雜的api

Concurrency
shiro 支持多線程應用的併發驗證,即如在一個線程中開啓另一個線程,能把權限自動傳播過去;

SessionDAO
DAO 大家都用過,數據訪問對象,用於會話的 CRUD,比如我們想把 Session 保存到數據庫,那麼可以實現自己的 SessionDAO,通過如 JDBC 寫到數據庫;比如想把 Session 放到 Memcached 中,可以實現自己的 Memcached SessionDAO;另外 SessionDAO 中可以使用 Cache 進行緩存,以提高性能;

5、安全數據源realm
   5.1、shiro自帶的默認的realm
  1. realm作用:Shiro 從 Realm 獲取安全數據
    默認自帶的realm:idae查看realm繼承關係,有默認實現和自定義繼承的realm 兩個概念
  2. principal : 主體的標示,可以有多個,但是需要具有唯一性,常見的有用戶名,手機號,郵箱等 credential:憑證, 一般就是密碼 所以一般我們說 principal + credential 就賬號 + 密碼 開發中,往往是自定義realm , 即集成 AuthorizingRealm
   5.2、shiro數據源使用.ini配置文件

在這裏插入圖片描述
ini配置文件內容:

# 格式 name=password,role1,role2,..roleN
[users]
# user 'root' with password 'secret' and the 'admin' role,
jack = 456, user
# user 'guest' with the password 'guest' and the 'guest' role
xdcalss = 123, root
# 格式 role=permission1,permission2...permissionN 也可以用通配符
# 下面配置user的權限爲所有video:find,video:buy,如果需要配置video全部操作crud 則 user = video:*
[roles]
user = video:find,video:buy
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *

快速啓動測試

  @Test
    public void test(){

        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");

        SecurityManager securityManager = factory.getInstance();

        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();

        //設置token  模擬用戶輸入賬號密碼
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","456");
        subject.login(usernamePasswordToken);

        System.out.println(subject.isAuthenticated());
        subject.hasRole("admin");
        System.out.println(subject.getPrincipal());

    }
5.3、shiro數據源realm使用jdbc方式注入

a、使用jdbc.ini文件

#注意 文件格式必須爲ini,編碼爲ANSI
#聲明Realm,指定realm類型
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
#配置數據源
#dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource=com.alibaba.druid.pool.DruidDataSource
# mysql-connector-java 5 用的驅動url是com.mysql.jdbc.Driver,mysql-connector-java6以後用的是 com.mysql.cj.jdbc.Driver
dataSource.driverClassName=com.mysql.cj.jdbc.Driver
#避免安全警告
dataSource.url=jdbc:mysql://localhost:3306/myshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
dataSource.username=wyy
dataSource.password=xxx
#指定數據源
jdbcRealm.dataSource=$dataSource

#開啓查找權限, 默認是false,不會去查找角色對應的權限,坑!!!!!
jdbcRealm.permissionsLookupEnabled=true
#指定SecurityManager的Realms實現,設置realms,可以有多個,用逗號隔開
securityManager.realms=$jdbcRealm

快速啓動

    @Test
    public void test2(){

        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcrealm.ini");

        SecurityManager securityManager = factory.getInstance();

        SecurityUtils.setSecurityManager(securityManager);

        Subject subject = SecurityUtils.getSubject();

        //設置token  模擬用戶輸入賬號密碼
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
        subject.login(usernamePasswordToken);

        System.out.println(subject.isAuthenticated());
        subject.hasRole("admin");
        System.out.println(subject.getPrincipal());
    }

b、使用Java配置值類

    @Test
    public void test1(){
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/myshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false");
        ds.setUsername("wyy");
        ds.setPassword("xxx");

        JdbcRealm jdbcRealm = new JdbcRealm();
        jdbcRealm.setPermissionsLookupEnabled(true);
        jdbcRealm.setDataSource(ds);
        securityManager.setRealm(jdbcRealm);

        SecurityUtils.setSecurityManager(securityManager);
        Subject subject = SecurityUtils.getSubject();
        //設置token  模擬用戶輸入賬號密碼
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
        subject.login(usernamePasswordToken);

        System.out.println(subject.isAuthenticated());
        subject.hasRole("admin");
        System.out.println(subject.getPrincipal());

    }

三、整合boot快速啓動

導入shiro依賴:

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

這裏使用的是shiro內置的realm

/**
 * @author wyy
 * @version 1.0
 * @date 2020/3/27 10:11
 * @description
 **/
public class QuickStart_shiro {


    private SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();

    private DefaultSecurityManager securityManager = new DefaultSecurityManager();

    @Before
    public void init(){
        //添加賬戶
        simpleAccountRealm.addAccount("zhangsan","123");
        //設置realm  構建 環境
        securityManager.setRealm(simpleAccountRealm);
    }

    @Test
    public void test(){
        //設置上下文
        SecurityUtils.setSecurityManager(securityManager);

        //當前操作主體
        Subject subject = SecurityUtils.getSubject();

        //設置token  模擬用戶輸入賬號密碼
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("zhangsan","1234");
        subject.login(usernamePasswordToken);

        Boolean isAccess = subject.isAuthenticated();

        System.out.println(isAccess);
    }

}

四、shiro自定義realm(重要)

步驟:

  • 創建一個AuthorizingRealm類 ,
  • 繼承樹AuthorizingRealm->AuthenticatingRealm->CachingRealm->Realm
  • 重寫授權方法 doGetAuthorizationInfo
  • 重寫認證方法 doGetAuthenticationInfo
1、重寫方法介紹:
  • 當用戶登陸的時候會調用 doGetAuthenticationInfo
  • 進行權限校驗的時候會調用: doGetAuthorizationInfo
2、一些被用到的對象介紹:
UsernamePasswordToken : 對應就是 shiro的token中有Principal和Credential
繼承樹:
UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken

SimpleAuthorizationInfo:代表用戶角色權限信息

SimpleAuthenticationInfo :代表該用戶的認證信息
3、自定義realm
/**
 * @author wyy
 * @version 1.0
 * @date 2020/4/7 14:38
 * @description
 **/
public class CustomRealm extends AuthorizingRealm {

    //創建模擬用戶
    private final Map<String,String> userInfoMap = new HashMap<>();

    {
        userInfoMap.put("jack","123");
        userInfoMap.put("admin","123");
    }
    
    //創建模擬權限
    private final Map<String,Set<String>> permissionMap = new HashMap<>();
    {
       Set<String> set1 = new HashSet<>();
        Set<String> set2 = new HashSet<>();
       set1.add("video:find");
       set1.add("video:buy");

       set2.add("video:add");
       permissionMap.put("jack",set1);
       permissionMap.put("admin",set2);
    }
    //創建模擬角色
    private final Map<String,Set<String>> roleMap = new HashMap<>();
    {
        Set<String> set1 = new HashSet<>();
        Set<String> set2 = new HashSet<>();
        set1.add("role1");
        set1.add("role2");

        set2.add("root");
        roleMap.put("jack",set1);
        roleMap.put("admin",set2);
    }

    //進行權限校驗的時候會調用: doGetAuthorizationInfo
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("權限:doGetAuthorizationInfo");
        String name = (String)principalCollection.getPrimaryPrincipal();
        Set<String> permission = getPermissionsFromDB(name);
        Set<String> roles = getRolesByNameFromDB(name);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRoles(roles);
        simpleAuthorizationInfo.addStringPermissions(permission);
        return simpleAuthorizationInfo;
    }

    private Set<String> getRolesByNameFromDB(String name) {
        return roleMap.get(name);
    }

    private Set<String> getPermissionsFromDB(String name) {
        return permissionMap.get(name);
    }

    //當用戶登陸的時候會調用 doGetAuthenticationInfo
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("認證:doGetAuthenticationInfo");
        String name = (String)authenticationToken.getPrincipal();
        String pwd = getPwdByNameFromDB(name);
       if(null == pwd || "".equals(pwd)){
           return null;
       }
       //pwd 可能需要一個加鹽操作
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name,pwd,this.getName());
        return simpleAuthenticationInfo;
    }

    private String getPwdByNameFromDB(String name) {
        return userInfoMap.get(name);
    }
}
4、自定義realm實例化
/**
 * @author wyy
 * @version 1.0
 * @date 2020/4/7 14:39
 * @description
 **/
public class QuickStart_shiro2 {

    private CustomRealm simpleAccountRealm = new CustomRealm();

    private DefaultSecurityManager securityManager = new DefaultSecurityManager();

    @Before
    public void init(){
        //設置realm  構建 環境
        securityManager.setRealm(simpleAccountRealm);

        //設置上下文
        SecurityUtils.setSecurityManager(securityManager);
    }

    @Test
    public void test(){
        //當前操作主體
        Subject subject = SecurityUtils.getSubject();

        //設置token  模擬用戶輸入賬號密碼
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken("jack","123");
        subject.login(usernamePasswordToken);

        Boolean isAccess = subject.isAuthenticated();
        subject.checkPermission("video:find");
        subject.checkPermission("video:buy");

        subject.hasRole("root");
        System.out.println(isAccess);
    }

}

五、shiro內置過濾器Fileter講解(重要)

1、DefaultFilter 及其內部的枚舉類
ssl :org.apache.shiro.web.filter.authz.SslFilter
user :org.apache.shiro.web.filter.authz.UserFilter
anon :org.apache.shiro.web.filter.authc.AnonymousFilter
port :org.apache.shiro.web.filter.authz.PortFilter
rest :org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
authc :org.apache.shiro.web.filter.authc.FormAuthenticationFilter
perms :org.apache.shiro.web.filter.authz.PermissionAuthorizationFilter
roles :org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
logout :org.apache.shiro.web.filter.authc.LogoutFilter
authcBasic :org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
noSessionCreation :org.apache.shiro.web.filter.session.NoSessionCreationFilter

是不是感覺一頭霧水 別急下面列出對應功能

       //匿名訪問  遊客訪問路徑
        filterChainDefinitionMap.put("/pub/**", "anon");

        //退出過濾器
        filterChainDefinitionMap.put("/user/logout", "logout");

        //登錄用戶才能訪問 
        filterChainDefinitionMap.put("/author/**", "authc");
         filterChainDefinitionMap.put("/author/**", "authcBasic");

        //只有admin管理員才能訪問
        filterChainDefinitionMap.put("/admin/**", "roles[admin]");

        //只有視頻修改權限的才能訪問
        filterChainDefinitionMap.put("/goods/video/update", "perms[video_update]");

        //authc : url 必須通過認證才能訪問
        //anon : url可以匿名訪問
        filterChainDefinitionMap.put("/**", "authc");
		port:org.apache.shiro.web.filter.authz.PortFilter
		端口攔截器, 可通過的端口。
		ssl:org.apache.shiro.web.filter.authz.SslFilter
		ssl攔截器,只有請求協議是https才能通過

這些過濾器分爲兩組,一組是認證過濾器,一組是授權過濾器。

  1. anon,authcBasic,auchc,user是第一組,
  2. perms,roles,ssl,rest,port是第二組

權限校驗的兩種方式

shiro權限控制註解和編程方式講解

1、註解方式
@RequiresRoles(value={"admin", "editor"}, logical= Logical.AND)
需要角色 admin 和 editor兩個角色 AND表示兩個同時成立
@RequiresPermissions (value={"user:add", "user:del"}, logical= Logical.OR)
需要權限 user:add 或 user:del權限其中一個,OR是或的意思。
@RequiresAuthentication
已經授過權,調用Subject.isAuthenticated()返回true
@RequiresUser
身份驗證或者通過記 住我登錄的
2、編碼形式
Subject subject = SecurityUtils.getSubject(); 
//基於角色判斷
if(subject.hasRole(“admin”)) {
	//有角色,有權限
} else {
	//無角色,無權限
	
}
//或者權限判斷
if(subject.isPermitted("/user/add")){
    //有權限
}else{
    //無權限
}
2、shiroFilterFactoryBean配置編寫(非常重要)
1、配置流程與思路
  • shirofilterfactorybean -》securitymanager
    • customsessionmanager
    • customrealm ->HashedCredentialsmatcher
  • sessionmanager
    • defaultsessionmanager :默認實現常用於JavaSE
    • servletcontainersessionmanager :web環境
    • defaultwebsessionmanager:常用於自定義實現
2、過濾器shiroFilterFactoryBean的實現 Java配置類的書寫
/**
 * @author wyy
 * @version 1.0
 * @Classname ShiroConfig
 * @date 2020/4/16 10:56
 * @description
 **/
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        System.out.println("ShiroFilterFactoryBean.shiroFilter() 執行了");

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //這裏設置了登錄接口  如果訪問了某個接口沒有登錄  就會調用這個接口(如果不是前後端分離就返回頁面)
        shiroFilterFactoryBean.setLoginUrl("/pub/need_login");

        //如果是前後端分離則不需要這個
        //shiroFilterFactoryBean.setSuccessUrl();

        //這個是用戶登錄了  但沒有權限 就會調用這個接口
        shiroFilterFactoryBean.setUnauthorizedUrl("/pub/need_permission");


        /**
        *攔截器路徑 坑1:部分路徑無法攔截,攔截效果時有時無,因爲使用了hashMap 是無序的應該使用linkedHashMap
        *原因在於過濾鏈執行順序是順序執行所以需要使用有序的linkedHashMap
      **/
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //匿名訪問  遊客訪問路徑
        filterChainDefinitionMap.put("/pub/**", "anon");

        //退出過濾器
        filterChainDefinitionMap.put("/user/logout", "logout");

        //登錄用戶才能訪問
        filterChainDefinitionMap.put("/author/**", "authc");

        //只有管理員才能訪問
        filterChainDefinitionMap.put("/admin/**", "roles[admin]");

        //視頻修改權限
        filterChainDefinitionMap.put("/goods/video/update","perms[video_update]");

        //坑2:過濾鏈是順序執行的,從上而下,一般來講/** 是放到最下面的

        //authc : url 必須通過認證才能訪問
        //anon : url可以匿名訪問
        filterChainDefinitionMap.put("/**","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(customRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }
    
    //自定義realm注入
    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();
        customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return customRealm;
    }
    
    //自定義sessionmanager注入
    @Bean
    public SessionManager sessionManager() {
    //使用自定義sessionmanager 具體寫法看  六—3
        CustomSessionManager customSessionManager = new CustomSessionManager();
    
        return customSessionManager;
    }
    
    //加密方式
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //設置散列算法 :這裏設置的MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //設置多重加密算法 :這裏設置的是2次加密(mad5(md5(xxx)))
        credentialsMatcher.setHashIterations(2);
        return credentialsMatcher;
    }
}

六、shiro緩存模塊

1、什麼是會話session?

用戶與程序的鏈接,程序可以根據session來區分不同的用戶。

2、什麼是會話管理器 sessionmanager?

會話管理器管理所有的subject的操作,是shiro的核心

核心方法:
//開啓一個session
Session start(SessionContext context);
//指定Key獲取session
Session getSession(SessionKey key)
shiro中的會話管理器有多個實現
SessionDao 會話存儲/持久化
SessionDAO AbstractSessionDAO CachingSessionDAO EnterpriseCacheSessionDAO MemorySessionDAO
核心方法
//創建
Serializable create(Session session);
//獲取
Session readSession(Serializable sessionId) throws UnknownSessionException;
//更新
void update(Session session) 
//刪除,會話過期時會調用
void delete(Session session);
//獲取活躍的session
Collection<Session> getActiveSessions();
3、自定義sessionManager驗證
/**
 * @author wyy
 * @version 1.0
 * @Classname CustomSessionManager
 * @date 2020/4/16 13:35
 * @description
 **/
public class CustomSessionManager extends DefaultWebSessionManager {


    private final static String AUTHORIZATION = "token";

    public CustomSessionManager(){
         super();
    }

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {

        String sessionId = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
        if(null != sessionId ){
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
           return sessionId;
        }else{
          return super.getSessionId(request,response);
        }
    }

}

七、api驗證

/**
 * @author wyy
 * @version 1.0
 * @Classname PublicController
 * @date 2020/4/20 10:03
 * @description
 **/
@RestController
@RequestMapping(name = "公共接口",value = "/pub")
public class PublicController {


    @RequestMapping(name = "設置的未登錄攔截接口",value = "/need_login")
    public JsonData needLogin(){
        return JsonData.buildSuccess(-2,"請先登錄");
    }

    @RequestMapping(name = "設置登錄但未授權的用戶攔截接口",value = "/need_permission")
    public JsonData needPermission(){
        return JsonData.buildSuccess(-3,"您沒有權限,請聯繫管理員!");
    }


    @RequestMapping(name = "初始化界面",value = "/index")
    public JsonData index(){
        List<String> goods = new ArrayList<>();
        goods.add("空調");
        goods.add("水壺");
        goods.add("電冰箱");
        goods.add("熱水器");
        goods.add("烤箱");
        return JsonData.buildSuccess(goods);
    }


    @RequestMapping(name = "登錄",value = "login")
    public JsonData login(@RequestBody UserBO userBO, HttpServletRequest request, HttpServletResponse response){
        Subject subject = SecurityUtils.getSubject();
        Map<String,Object> map = new HashMap<>(16);
        try {
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userBO.getName(), userBO.getPwd());
            subject.login(usernamePasswordToken);
            map.put("token",subject.getSession().getId());
        }catch (Exception e){
            map.put("msg","賬號或密碼不存在!");
        }
        return JsonData.buildSuccess(map);
    }
}

1、遊客訪問接口:不需要登錄就可以訪問

在這裏插入圖片描述

@RestController
@RequestMapping(value = "author")
public class OrderController {

    @RequestMapping(value = "listOrder")
    public JsonData ListOrder(){
        Map<String,String> map = new HashMap<>(16);
        map.put("springboot基礎","19.00元");
        map.put("redis基礎","29.00元");
        map.put("activeMq基礎","13.00元");
        return JsonData.buildSuccess(map);

    }

}
2、author:需要用戶登錄才能訪問接口

在這裏插入圖片描述
在這裏插入圖片描述

@RestController
@RequestMapping(value = "/goods/video")
public class VideoController {


    @RequestMapping(value = "update")
    public JsonData videoUpdate(){
        return JsonData.buildSuccess();
    }
}
3、需要有video_update 權限的用戶才能訪問

權限明細表
角色權限關聯表
角色用戶關聯表
用戶表

在這裏插入圖片描述
這裏只有Jack有更新權限所以John是沒有權限訪問該接口的

/**
 * @author wyy
 * @version 1.0
 * @date 2020/4/14 9:46
 * @description
 **/
@RestController
@RequestMapping(name = "用戶模塊", value = "admin")
public class UserController {

    @RequestMapping(name = "根據id獲取角色所有權限",value = "/getPermissionById")
    public List<Role> getRoles(@RequestParam(value = "id") Integer id){
      return userService.getRoles(id);
    }

}

在這裏插入圖片描述
在這裏插入圖片描述

4、注意點:

4.1、登錄時,我們輸入的是明文,但是realm使用了一層MD5加密,所以你的數據庫裏存儲的密碼應該要是密文才能校驗通過,否則就會出現下面錯誤
在這裏插入圖片描述
當然上面的登錄例子裏面進行了try catch 操作所以不會拋錯
4.2、登錄獲取的token並非永久,如果不設置過期時間shiro默認30分鐘,這裏我們在sessionmanager裏面配置了session過期時間18s
sessionid過期時間設置
4.3、前端傳的憑證名稱是由後端sessionmanager規定
憑證設置

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章