SpringBoot-Shiro

Shiro

1. QuickStart

1. 導入依賴

這裏同時導入了log4j, Shiro默認的日誌是commons-logginghtml

<dependencies>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.6.0</version>
    </dependency>

    <!-- configure logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <scope>runtime</scope>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <scope>runtime</scope>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <scope>runtime</scope>
        <version>1.2.17</version>
    </dependency>
</dependencies>

2. 配置shiro

1. log4j配置

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

# General Apache libraries
log4j.logger.org.apache=WARN

# Spring
log4j.logger.org.springframework=WARN

# Default Shiro logging
log4j.logger.org.apache.shiro=INFO

# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

2. shiro配置

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#
# =============================================================================
# Quickstart INI Realm configuration
#
# For those that might not understand the references in this file, the
# definitions are all based on the classic Mel Brooks' film "Spaceballs". ;)
# =============================================================================

# -----------------------------------------------------------------------------
# Users and their assigned roles
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
# -----------------------------------------------------------------------------
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5

3. QuickStart

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Quickstart {

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        // for this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton.  Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps.  That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:

        // get the currently executing user:
        //獲取當前的用戶對象 Subject
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        //經過當前用戶拿到 session (能夠脫離Web)
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("Retrieved the correct value! [" + value + "]");
        }

        // let's login the current user so we can check against roles and permissions:
        //判斷當前的用戶是否被認證
        if (!currentUser.isAuthenticated()) {
            //Token :   令牌, 此處沒有獲取, 隨機設置
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            //設置記住我
            token.setRememberMe(true);
            try {
                //執行登陸操做
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            //認證異常(總的異常)
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }

        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //all done - log out!
        //註銷
        currentUser.logout();

        //結束啓動
        System.exit(0);
    }
}

2. SpringBoot中集成

Shiro三大核心前端

  • Subject: 用戶
  • SecurityManager: 管理全部用戶
  • Realm: 鏈接數據

1. 導入springboot整合shiro的包

<!--shiro整合包-->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring-boot-web-starter</artifactId>
   <version>1.6.0</version>
</dependency>

2. 自定義UserRealm

package com.wang.config;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

//自定義的 UserRealm, 繼承AuthorizingRealm便可
public class UserRealm extends AuthorizingRealm {

    //受權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("執行了 => AuthorizationInfo 受權");
        return null;
    }

    //認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("執行了 => AuthenticationInfo 認證");
        return null;
    }
}

注意java

  • 想要自定義Realm, 繼承AuthorizingRealm便可
  • 要重寫抽象類AuthorizationInfo和AuthenticationInfo

3. 配置Shiro

package com.wang.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean : 3
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //關聯SecurityManager, 設置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //添加shiro的內置過濾器
        /*
            anon: 無需認證, 就能夠訪問
            authc: 必須認證了才能訪問
            user: 必須擁有 記住我 功能才能訪問
            perms: 擁有對於某個資源的權限才能訪問
            role: 擁有某個角色權限才能訪問
         */
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

//        filterChainDefinitionMap.put("/user/add", "authc");
//        filterChainDefinitionMap.put("/user/update", "authc");
        filterChainDefinitionMap.put("/user/*", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        //設置登陸的請求
        shiroFilterFactoryBean.setLoginUrl("/toLogin");


        return shiroFilterFactoryBean;
    }

    //DefaultWebSecurityManager : 2
    //@Qualifier() 利用bean的id注入, 在註解託管中即爲方法名
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //關聯UserRealm
        securityManager.setRealm(userRealm);

        return securityManager;
    }

    //建立realm對象, 須要自定義 : 1
    //將本身定義的Realm註冊爲Bean, 被SpringBoot託管
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }
}

注意:git

  • 不要忘記註冊Bean
  • @Qualifier() 利用bean的id注入, 在註解託管中即爲方法名
  • 實際寫法的過程應該爲: UserRealm --> DefaultWebSecurityManager --> ShiroFilterFactoryBean
  • Shiro過濾器的經過k-v的方法放入參數, 有如下五個參數
    • anon: 無需認證, 就能夠訪問github

    • authc: 必須認證了才能訪問web

    • user: 必須擁有 記住我 功能才能訪問spring

    • perms: 擁有對於某個資源的權限才能訪問數據庫

    • role: 擁有某個角色權限才能訪問express

4. Controller

package com.wang.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MyController {

    @RequestMapping({"/", "/index"})
    public String toIndex(Model model) {
        model.addAttribute("msg", "Hello, Shiro!");
        return "index";
    }

    @RequestMapping("/user/add")
    public String add() {
        return "user/add";
    }

    @RequestMapping("/user/update")
    public String update() {
        return "user/update";
    }

    @RequestMapping("/toLogin")
    public String toLogin() {
        return "login";
    }
}

前端頁面代碼略apache

3. Shiro用戶認證

1. 用戶登陸判斷

這裏寫在controller中, 利用不一樣的結果輸出提示信息並進行跳轉

@RequestMapping("/login")
public String login(String username, String password, Model model) {
    //獲取當前的用戶
    Subject subject = SecurityUtils.getSubject();
    //封裝用戶的登陸數據
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    //執行登陸的方法, 若是沒有異常, 說明登陸OK
    try {
        subject.login(token);
        return "index";
    } catch (UnknownAccountException e) {
        //用戶名不存在
        model.addAttribute("msg", "用戶名錯誤");
        return "login";
    } catch (IncorrectCredentialsException e) {
        //密碼不存在
        model.addAttribute("msg", "密碼錯誤");
        return  "login";
    }

注意

  • 經過Subject對象得到當前的用戶 ==> Subject subject = SecurityUtils.getSubject();
  • 要將用戶的信息封裝在token中
  • subject.login(token); ==> 便可進行用戶登陸
  • 判斷用戶認證結果, 這裏經過捕獲不一樣的異常進行!

2. 用戶認證配置

在自定義的UserRealm中, 進行配置

//認證
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("執行了 => AuthenticationInfo 認證");

    //用戶名, 密碼 ==> 數據庫中取
    String name = "root";
    String password = "123456";

    UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;

    //用戶名認證
    if (!userToken.getUsername().equals(name)) {
        //拋出異常 UnknownAccountException
        return null;
    }

    //密碼認證 : shiro作
    return new SimpleAuthenticationInfo("", password, "");

}

注意

  • 傳入的參數即爲token, 要進行類型轉換 ==> UsernamePasswordToken
  • 對token進行操做便可配置, 返回值爲null爲對應的方法的異常
  • 密碼認證shiro作, 不須要咱們進行操做, 只須要返回SimpleAuthenticationInfo, 其中的參數傳遞password等

4. 整合Shiro與Mybatis和Thymeleaf

1. 導入依賴

Shiro不須要導入與Mybatis的整合, 只須要導入與thymeleaf的整合包

<!--shiro整合thymeleaf-->
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
   <groupId>com.github.theborakompanioni</groupId>
   <artifactId>thymeleaf-extras-shiro</artifactId>
   <version>2.0.0</version>
</dependency>

2. 配置Shiro

package com.wang.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

@Configuration
public class ShiroConfig {

    //ShiroFilterFactoryBean : 3
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //關聯SecurityManager, 設置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //添加shiro的內置過濾器
        /*
            anon: 無需認證, 就能夠訪問
            authc: 必須認證了才能訪問
            user: 必須擁有 記住我 功能才能訪問
            perms: 擁有對於某個資源的權限才能訪問
            role: 擁有某個角色權限才能訪問
         */
        //攔截
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

//        filterChainDefinitionMap.put("/user/add", "authc");
//        filterChainDefinitionMap.put("/user/update", "authc");
        //受權
        filterChainDefinitionMap.put("/user/add", "perms[user:add]");
        filterChainDefinitionMap.put("/user/update", "perms[user:update]");

        filterChainDefinitionMap.put("/user/*", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        //設置登陸的請求
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        //未受權頁面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noauth");


        return shiroFilterFactoryBean;
    }

    //DefaultWebSecurityManager : 2
    //@Qualifier() 利用bean的id注入, 在註解託管中即爲方法名
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //關聯UserRealm
        securityManager.setRealm(userRealm);

        return securityManager;
    }

    //建立realm對象, 須要自定義 : 1
    //將本身定義的Realm註冊爲Bean, 被SpringBoot託管
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

    //整合ShiroDialect: 用來整合 shiro thymeleaf
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }
}

注意

  • 配置中的攔截器, 登陸請求都在ShiroFilterFactoryBean中配置, 這是因爲在Shiro運行時, 他是最後一層直接和用戶交互的!
  • setFilterChainDefinitionMap方法以K-V的方式儲存過濾器的URL和權限信息
    • perms資源過濾器要寫成perms[XXX], XXX爲子字符串, 能夠在數據庫中儲存對應的權限字段, 這裏是比對的標準
  • 要整合Thymeleaf, 就要註冊ShiroDialect這個Bean
  • 配置中不涉及數據庫的操做

3. 在自定義的Realm中配置受權和認證

package com.wang.config;

import com.wang.pojo.User;
import com.wang.service.UserServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

//自定義的 UserRealm, 繼承AuthorizingRealm便可
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserServiceImpl userService;

    //受權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("執行了 => AuthorizationInfo 受權");

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //拿到當前登陸的這個對象, user在下面已經放到了subject中
        Subject subject = SecurityUtils.getSubject();
        //拿到user對象
        User currentUser = (User) subject.getPrincipal();
        //放到perms中, 在ShiroConfig中以K-V調用
        info.addStringPermission(currentUser.getPerms());

        return info;
    }

    //認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("執行了 => AuthenticationInfo 認證");

        //用戶名, 密碼 ==> 數據庫中取
        //從token中得到用戶名
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;

        String username = userToken.getUsername();
        User user = userService.queryUserByName(username);

        //輸入的用戶名在數據庫中不存在
        if (user == null) {
            return null;
        }

        Subject currentSubject = SecurityUtils.getSubject();
        Session session = currentSubject.getSession();
        session.setAttribute("loginUser", user);

        String password = user.getPwd();

        //密碼認證 : shiro作(password與token從前端取出的密碼進行比較)
        //此處傳入一個user, 放到了Subject中
        return new SimpleAuthenticationInfo(user, password, "");

    }
}

注意

  • 受權

    • 此處要和數據庫交互, 得到用戶的信息以及權限, 只須要自動裝配Service的實現類便可
    • 經過 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();建立一個受權的對象
    • 經過Subject subject = SecurityUtils.getSubject();拿到當前的對象, 進行受權操做
    • 經過User currentUser = (User) subject.getPrincipal(); 能夠將Subject的字段和User實體類一一對應
    • 經過 info.addStringPermission(currentUser.getPerms()); 將User中的權限的字段放到Shiro權限驗證中(Perms["XXX"])
    • 注意要返回受權的對象
  • 認證

    • 用戶名和密碼已經放在了token中 UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken; 這個token是從controller層中利用從前端的數據封裝好的

    • 這裏能夠設置Subject對象的session, 存放一個loginUser字段, 判斷是否有User從而選擇是否在前端顯示登錄的連接, 這裏的session不是Web中的session, 是Shiro自帶的, 全局都能用(和web的session差很少)

    • SimpleAuthenticationInfo對象一樣的是返回咱們設置完的認證對象, 參數設置以下

      • principal   the 'primary' principal associated with the specified realm.
        credentials the credentials that verify the given principal.
        realmName   the realm from where the principal and credentials were acquired.
        public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName)
    • 此處的用戶名, 密碼, 以及用戶對象都從數據庫中取出

    • 此處的放回值 return new SimpleAuthenticationInfo(user, password, ""); 裏面傳遞了咱們從數據庫中取出的user, 在受權時因爲關聯了字段, 所以Shiro會幫咱們從user中取出perms對應的字段, 和config中的過濾器進行比較

4. Controller

@RequestMapping("/login")
public String login(String username, String password, Model model) {
    //獲取當前的用戶
    Subject subject = SecurityUtils.getSubject();
    //封裝用戶的登陸數據
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    //執行登陸的方法, 若是沒有異常, 說明登陸OK
    try {
        subject.login(token);
        return "index";
    } catch (UnknownAccountException e) {
        //用戶名不存在
        model.addAttribute("msg", "用戶名錯誤");
        return "login";
    } catch (IncorrectCredentialsException e) {
        //密碼不存在
        model.addAttribute("msg", "密碼錯誤");
        return  "login";
    }
}

注意

  • Controller層中必定要接收前端的username和password, 並經過UsernamePasswordToken對象給Shiro一個token從而實現Realm層的調用驗證
  • 一樣的, 要獲取當前用戶的Subject, 直接調用login方法, 放入token便可進行登陸的驗證, 經過不一樣的異常類型進行提示和跳轉

5. thymeleaf

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>首頁</h1>
<p>
    <span th:text="${msg}"></span>
</p>
<p th:if="${session.loginUser==null}">
    <a th:href="@{/toLogin}">登陸</a>
</p>

<hr>

<div shiro:hasPermission="user:add">
    <a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update">
    <a th:href="@{/user/update}">update</a>
</div>


</body>
</html>

注意

  • 要引入命名空間 xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
  • shiro整合的格式相似thymeleaf, 以shiro:開頭, 後面跟屬性名
  • shiro:hasPermission="XXX"進行權限控制, XXX爲咱們在config中設定的權限的屬性名
  • 此處的session爲咱們在Shiro中定義的session, 裏面存放了咱們自定義的屬性以及值
相關文章
相關標籤/搜索