springBoot的shiro的簡(jiǎn)單項(xiàng)目部署

springboot2.0框架下使用Shiro

介紹

Shiro是Apache旗下的開(kāi)源項(xiàng)目,是一個(gè)簡(jiǎn)單易用的安全框架砾跃,提供包括認(rèn)證骏啰、授權(quán)、加密抽高、會(huì)話管理等諸多功能判耕。Shiro使用了比較簡(jiǎn)單易懂易于使用的授權(quán)方式撕予。Shiro屬于輕量級(jí)框架唱遭,配置簡(jiǎn)單遣总,應(yīng)用廣泛构蹬。在很多優(yōu)秀的開(kāi)源項(xiàng)目之中都有使用六水。

搭建springboot种远,網(wǎng)頁(yè)部分

創(chuàng)建項(xiàng)目

搭建springboot開(kāi)發(fā)環(huán)境

打開(kāi)idea盆耽,點(diǎn)擊文件(file)-->新建(new)-->新建文件(Project)

shiro-01.png

之后就會(huì)進(jìn)入idea的新建項(xiàng)目之中轰绵,這里點(diǎn)擊這個(gè)樹(shù)葉加一個(gè)開(kāi)關(guān)按鈕的這個(gè)標(biāo)志莹桅,之后點(diǎn)擊下一步就可以了

shiro-02.png

之后這個(gè)就是昌执,真正的配置界面,填好信息诈泼,就可以點(diǎn)擊下一步懂拾,這里面比較重要的是這個(gè)javaVersion這里,默認(rèn)是11版本厂汗。需要用戶自己根據(jù)實(shí)際情況選擇版本

shiro-03.png

在依賴選擇這里委粉,只選Web里面的spring web選項(xiàng)就可以了。然后點(diǎn)擊下一步娶桦。

shiro-04.png

這里一般只看上面就可以了贾节,項(xiàng)目名和項(xiàng)目位置最后面的名字可以不一致,不影響程序的運(yùn)行

shiro-05.png

點(diǎn)擊完成衷畦,再等maven項(xiàng)目下載所需的依賴就可以了栗涂。依賴下載完成,項(xiàng)目結(jié)構(gòu)如下祈争。(target在項(xiàng)目運(yùn)行時(shí)斤程,會(huì)生成)

shiro-06.png

添加依賴項(xiàng)

打開(kāi)pom.xml文件在<dependencies>標(biāo)簽內(nèi)添加依依賴

org.apache.shiro.shiro-all是本文中需要使用的的依賴

com.alibaba.fastjson是一個(gè)json格式文件處理工具,可能會(huì)用到

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-all</artifactId>
    <version>1.6.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.74</version>
</dependency>

打開(kāi)idea右側(cè)的maven的,點(diǎn)擊如圖所示刷新按鈕忿墅,下載依賴包

shiro-07.png

搭建網(wǎng)頁(yè)前端內(nèi)容

用幾個(gè)前端網(wǎng)頁(yè)扁藕,對(duì)接后端數(shù)據(jù),方便調(diào)試疚脐。

第一個(gè)是首頁(yè)面(需要登錄才能進(jìn)入)

第二個(gè)是用戶的登錄頁(yè)面

第三個(gè)是提示用戶沒(méi)有授權(quán)的頁(yè)面亿柑,他會(huì)自動(dòng)跳轉(zhuǎn)到首頁(yè)面或者登錄頁(yè)面。

首先是第一個(gè)頁(yè)面棍弄,簡(jiǎn)單的使用html網(wǎng)頁(yè)寫一個(gè)大大的首頁(yè)望薄,并對(duì)其簡(jiǎn)單的美化一下,非常清楚

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首頁(yè)</title>
</head>
<body style="margin: 0;padding: 0;border-style: none">
<h1 style="margin:0;padding: 0;text-align: center;background-color: #00ced1;color: #9400d3;font-size: 150px;text-shadow: 5px 5px 2px #6000a3;">
    首頁(yè)主體
</h1>
</body>
</html>

然后是第二個(gè)頁(yè)面呼畸,登錄頁(yè)面痕支,使用form表單,action內(nèi)容千萬(wàn)不要使用域名(ip)+端口之后是路徑這種方式蛮原,則會(huì)導(dǎo)致每次提交表單卧须,都會(huì)導(dǎo)致session不一致,直接寫路徑就好瞬痘。還是死一樣故慈,簡(jiǎn)單的美化一下就好

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>系統(tǒng)登錄</title>
    <style>
        input[type="text"], input[type="password"] {
            margin: 0 2px;
            height: 35px;
            width: 100%;
        }

        input[type="submit"], input[type="button"] {
            height: 35px;
            width: 80px;
        }

        td {
            font-size: 20px;
            text-align: right;
        }
        tr{

        }
        table {
            padding: 0 20px 0 0 ;
            width: 30%;
            border-style: solid;
            border-width: 1px;
        }

    </style>
</head>
<body>
<center>
    <form action="/user/login" method="get" style="margin-top: 10%;" target="_self">
        <table>
            <tr>
                <td>用戶名</td>
                <td><input type="text" name="username"/></td>
            </tr>
            <tr>
                <td>密碼</td>
                <td><input type="password" name="password"/></td>
            </tr>
            <tr>
                <td colspan="2"><input type="button" value="沒(méi)用的按鈕"style="margin-left:30%; ">
                    <input type="submit" value="登錄" style="margin-left:10%; "></td>
            </tr>
        </table>
    </form>
</center>
</body>
</html>

之后就是用戶沒(méi)有權(quán)限時(shí)跳轉(zhuǎn)的頁(yè)面,這里設(shè)置為打開(kāi)頁(yè)面5秒后框全,自動(dòng)跳轉(zhuǎn)到首頁(yè)面或者登錄頁(yè)面察绷。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>你沒(méi)有該權(quán)限訪問(wèn)</title>
</head>
<body>
<div style="margin: 100px 0 0 40%;font-size: 30px">
    <a id="aa123" href="/login.html">5秒后,跳轉(zhuǎn)登錄頁(yè)面....</a>
</div>
</body>
<script>
    let time = 5;
    let interval = setInterval(setText, 1000)
    setTimeout(toLogin, 5000);

    function toLogin() {
        window.open("/login.html","_self")
    }

    function setText() {
        time--;
        document.getElementById("aa123").innerText = time + "秒后津辩,跳轉(zhuǎn)登錄頁(yè)面...."
        if (time===0){
            clearInterval(interval)
        }
    }
</script>
</html>

java部分

介紹

考慮到sql拆撼,mybatis,配置過(guò)于繁雜喘沿,所以項(xiàng)目中使用靜態(tài)的數(shù)據(jù)代替sql闸度。再模擬寫一個(gè)service層的部分。

啟動(dòng)項(xiàng)

在項(xiàng)目的啟動(dòng)項(xiàng)Application類中設(shè)置一個(gè)新注解蚜印,這里使用@ComponentScan注解來(lái)掃描注解類莺禁,為了省事,直接使用**號(hào)掃描

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = {
        //掃描包窄赋,加載注解
        "com.eelinker.shiro.**",
        "com.eelinker.shiro.**.**",
        "com.eelinker.shiro.**.**.**"
})
public class ShiroApplication {
    public static void main(String[] args) {
        SpringApplication.run(ShiroApplication.class, args);
    }
}

Service層

User

首先需要?jiǎng)?chuàng)建一個(gè)實(shí)體類哟冬,User,用戶的數(shù)據(jù)信息封裝,get和set以及toString方法省略忆绰。這里面有一個(gè)Role的類是沒(méi)有定義的浩峡,代表的是用戶的訪問(wèn)權(quán)限。

public class User {
    //用戶id
    private int id;
    //用戶名
    private String username;
    //用戶密碼
    private String password;
    //用戶權(quán)限
    private Role role;
}

Role

這里設(shè)定了老板權(quán)限错敢,員工權(quán)限翰灾,檢查人員權(quán)限,以及顧客權(quán)限三大類型,詳細(xì)的權(quán)限還分為管理權(quán)(administration)纸淮,制作權(quán)(make)平斩,檢查權(quán)(check)

顧客只能訪問(wèn)最基本的訪問(wèn)權(quán)限,其他的人都默認(rèn)擁有顧客的訪問(wèn)權(quán)限萎馅,這些訪問(wèn)權(quán)限都需要登錄双戳,不登錄都會(huì)默認(rèn)跳轉(zhuǎn)到登錄界面。為了區(qū)分這些權(quán)限糜芳,特地的做了一個(gè)枚舉類(不用枚舉也行,用字符串?dāng)?shù)據(jù)代替也是可以的)

package com.eelinker.shiro.entity;

import java.util.HashSet;
import java.util.Set;

/**
 *角色類型
 *
 * @author Administrator
 */
public enum Role {

    //老板 所有權(quán)限
    boss(permissionType.administration, permissionType.make, permissionType.check),

    //員工 制作權(quán)限
    staff(permissionType.make),

    //檢查人員 查詢權(quán)限
    checker(permissionType.check),

    //顧客 使用權(quán)限
    customer;

    private final permissionType[] types;

    Role(permissionType... types) {
        this.types = types;
    }
    /**
     * 權(quán)限類型
     */
    public enum permissionType {
        administration,
        make,
        check;

        @Override
        public String toString() {
            return name();
        }
    }
    /**
     * 獲取用戶的權(quán)限名稱
     */
    public Set<String> toSetValue() {
        Set<String> permsSet = new HashSet<>();
        for (permissionType type : types) {
            System.out.println(type.name());
            permsSet.add(type.name());
        }
        return permsSet;
    }
}

UserService

在將用戶的信息封裝好之后魄衅,接下來(lái)就是寫Service的代碼了峭竣,因?yàn)檫@里只是演示,所以只需要展示用戶的訪問(wèn)權(quán)限就行了晃虫。靜態(tài)的List集合代替數(shù)據(jù)庫(kù)中的內(nèi)容皆撩,select代替mybatis的查詢語(yǔ)句封裝。根據(jù)用戶名查詢用戶的具體數(shù)據(jù)哲银。

import com.eelinker.shiro.entity.Role;
import com.eelinker.shiro.entity.User;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * Created System: Windows7
 * Created Code by  Administrator
 * Created Date: 2022/1/13 16:05
 *
 * @author Administrator
 */
@Service
public class UserService {
    private static List<User> userList = new ArrayList<User>() {
        {
            add(new User(1, "admin", "admin123", Role.boss));
            add(new User(2, "checker", "checker123", Role.checker));
            add(new User(3, "staff_zhang", "staff003", Role.staff));
            add(new User(4, "staff_li", "staff004", Role.staff));
            add(new User(5, "staff_wang", "staff005", Role.staff));
            add(new User(6, "staff_zhao", "staff006", Role.staff));
            add(new User(7, "customer7", "customer", Role.customer));
            add(new User(8, "customer8", "customer", Role.customer));
            add(new User(9, "customer9", "customer", Role.customer));
            add(new User(10, "customer10", "customer", Role.customer));
            add(new User(11, "customer11", "customer", Role.customer));
        }
    };

    private static User select(String username) {
        for (User user : userList) {
            if (user.getUsername().equals(username)) {
                return user;
            }
        }
        return null;
    }

}

shiro配置部分

讀取yml配置文件數(shù)據(jù)內(nèi)容

在springboot中是可以自己設(shè)置yml中的鍵值對(duì)的扛吞。這樣方便開(kāi)發(fā)者修改,調(diào)試荆责。這里是我自定義的shiro配置滥比。使用shiro作為前綴。在shiro的下一級(jí)子參數(shù)中做院,login-url這個(gè)key值寫成loginUrl也是可以的盲泛。

配置文件的名稱定位application-shiro.yml(后綴改為yaml也是可以的)

shiro:
  #登錄地址url
  login-url: /login.html
  #未經(jīng)授權(quán)的跳轉(zhuǎn)
  unauthorized-url: /unauthor.html
  #登錄成功的url
  success-url: /index.html
  filter-class:
    - anon,org.apache.shiro.web.filter.authc.AnonymousFilter
    - logout,org.apache.shiro.web.filter.authc.LogoutFilter
  #路徑過(guò)濾規(guī)則
  filter-rule:
    - /**.html,anon
    - /index/**,anon
    - /user/**,anon
    #注銷登錄的地址,不需要開(kāi)發(fā)者寫相關(guān)的代碼或業(yè)務(wù)键耕,也能退出登錄
    - /logout,logout
    #需要有這個(gè)名稱的權(quán)限才能訪問(wèn)這個(gè)路徑(這里沒(méi)有提登錄寺滚,不登錄也會(huì)觸發(fā),之后跳轉(zhuǎn)到unauthorized-url)
    - /select/**,perms["check"]
    - /**,authc

在寫好了配置之后屈雄,這還是不能讓開(kāi)發(fā)者直接讀取村视。需要在主配置相中配置,也就是application.yml這個(gè)文件酒奶。

下面這里server.port這里是修改項(xiàng)目端口的位置

spring.profiles.active這里是配置springboot蚁孔,讀取上面配置的application-shiro.yml文件。

server:
  port: 8052
spring:
  profiles:
    active: shiro
  messages:
    encoding: UTF-8
  main:
    allow-bean-definition-overriding: true

在配置好上面信息之后讥蟆,就可以創(chuàng)建一個(gè)實(shí)體類封裝這些數(shù)據(jù)了勒虾。代碼如下。因?yàn)榕渲弥行枰氖且唤M鍵值對(duì)而不是list集合瘸彤,所以可以用“,”隔開(kāi)兩個(gè)兩個(gè)數(shù)據(jù)前面的是路徑和面的是具體的內(nèi)容

filterClass是攔截器的類加載修然,在getFilterClassValue方法中會(huì)創(chuàng)建出這一個(gè)類,然后返回。

filterRule這是攔截路徑愕宋,前面的是路徑玻靡,后面的是允許訪問(wèn)的條件

@Component
@ConfigurationProperties(prefix = "shiro")
public class ShiroConfigReader {
    private String loginUrl;
    private String unauthorizedUrl;
    private String successUrl;
    private List<String> filterClass;
    private List<String> filterRule;
    // get set toString省略,在idea中可以使用alt+insert鍵創(chuàng)建
    public Map<String, Filter> getFilterClassValue() throws Exception {
        Map<String, Filter> map = new HashMap<>();
        if (filterClass != null) {
            for (String string : filterClass) {
                String[] keyAndValue = string.split(",");
                if (keyAndValue.length == 2) {
                    Class aClass = ClassLoader.getSystemClassLoader().loadClass(keyAndValue[1]);
                    Object object = aClass.newInstance();
                    if (object instanceof Filter) {
                        map.put(keyAndValue[0], (Filter) object);
                    }
                }
            }
            if (map.size() != 0) {
                return map;
            }
        }
        throw new IllegalAccessException("The parameter is empty or the value is incorrect");
    }

    public Map<String, String> getFilterRuleMap() {
        Map<String, String> map = new HashMap<>();
        if (filterRule != null) {
            for (String string : filterRule) {

                String[] keyAndValue = new String[2];
                int index = string.indexOf(",");
                if (index != -1) {
                    keyAndValue[0] = string.substring(0, index);
                    keyAndValue[1] = string.substring(index + 1);
                    map.put(keyAndValue[0], keyAndValue[1]);
                } else {
                    throw new IllegalArgumentException("The yml file parameter is incorrect");
                }
            }
            return map;
        }
        throw new IllegalArgumentException("The yml file parameter is incorrect");
    }
}

拿到這些配置信息之后中贝,就可以根據(jù)內(nèi)容讀取數(shù)據(jù)信息囤捻,之后的修改和添加都可以在yml中進(jìn)行。之前的上一個(gè)java文件中有@Component這個(gè)注解邻寿,所以在下面的shiro中可以使用@Autowired讀取蝎土。在shiroFilterFactoryBean讀取加載這些信息

import com.eelinker.shiro.config.reader.ShiroConfigReader;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * springBoot整合jwt實(shí)現(xiàn)認(rèn)證有三個(gè)不一樣的地方,對(duì)應(yīng)下面abc
 *
 * @author Administrator
 */
@Configuration
public class ShiroConfig {
    @Autowired
    private ShiroConfigReader reader;

    @Bean
    public Realm realm() {
        return new MyRealm();
    }

    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm());
        // 關(guān)閉 ShiroDAO 功能
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        // 不需要將 Shiro Session 中的東西存到任何地方(包括 Http Session 中)
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        //禁止Subject的getSession方法
//        securityManager.setSubjectFactory(subjectFactory());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() throws Exception {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager());
        shiroFilter.setLoginUrl(reader.getLoginUrl());
        shiroFilter.setUnauthorizedUrl(reader.getUnauthorizedUrl());
        shiroFilter.setFilters(reader.getFilterClassValue());
        shiroFilter.setFilterChainDefinitionMap(reader.getFilterRuleMap());
        return shiroFilter;
    }
}

在第一個(gè)的@Bean中里面創(chuàng)建了一個(gè)MyRealm這個(gè)類的對(duì)象绣否。這里就是用戶的授權(quán)認(rèn)證所需要用到的內(nèi)容誊涯。

doGetAuthorizationInfo方法,判斷當(dāng)前訪問(wèn)的用戶是否具有訪問(wèn)權(quán)限蒜撮,例如檢查暴构,管理制作權(quán)限。這里會(huì)查詢用戶的數(shù)據(jù)信息段磨,使用到數(shù)據(jù)庫(kù)驗(yàn)證取逾,讀取用戶信息進(jìn)行驗(yàn)證。

doGetAuthenticationInfo這個(gè)方法師在用戶調(diào)用subject.login(token)時(shí)苹支,會(huì)進(jìn)入到這里進(jìn)行權(quán)限的配置砾隅。


import com.eelinker.shiro.entity.User;
import com.eelinker.shiro.service.UserService;
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.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserService service;

    /**
     * 用戶身份認(rèn)證
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        String username = (String) principalCollection.getPrimaryPrincipal();
        User user = service.selectByUsername(username);
        // 權(quán)限Set集合
        Set<String> permsSet = user.getRole().toSetValue();
        // 返回權(quán)限
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 用戶權(quán)限認(rèn)證(登錄)
     * 這個(gè)token就是從過(guò)濾器中傳入的jwtToken
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //這里返回的是類似賬號(hào)密碼的東西,但是jwtToken都是jwt字符串沐序。還需要一個(gè)該Realm的類名
        return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), "MyRealm");
    }

}

但是查詢用戶所擁有的權(quán)限這里琉用,沒(méi)有userService.selectByUsername方法,所以到userService中添加一個(gè)這個(gè)方法

public User selectByUsername(String username) {
    for (User user : userList) {
        if (user.getUsername().equals(username)) {
            return user;
        }
    }
    return null;
}

Controller簡(jiǎn)單創(chuàng)建

在前面創(chuàng)建的頁(yè)面中有一個(gè)登錄頁(yè)面,那么現(xiàn)在就進(jìn)行登錄操作策幼。類的創(chuàng)建就省略了邑时,這里自動(dòng)注入了一個(gè)UserService。mapping中可以驗(yàn)證

@Autowired
private UserService userService;

/**
 * 用戶登錄
 *
 * @param username
 * @param password
 * @return
 */
@RequestMapping("/user/login")
public String login(@RequestParam String username, @RequestParam String password) {
    User user = userService.login(username, password);
    if (user != null) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        subject.login(token);
        return "redirect:/index.html";
    }
    return "redirect:/login.html";
}

但是目前沒(méi)有寫驗(yàn)證的service代碼特姐【穑回到UserService添加如下代碼,驗(yàn)證用戶名和密碼是否正確唐含。

public User login(String username, String password) {
    User user = select(username);
    if (user == null) {
        throw new NullPointerException("User does not exist !");
    }
    if (user.getPassword().equals(password)) {
        return user;
    } else {
        System.out.println("密碼錯(cuò)誤");
    }
    return null;
}

從下圖中可以看到浅浮,先輸入的純域名,之后跳轉(zhuǎn)到了login.html就表名shiro的攔截頁(yè)面起了效果

shiro-08.png

好捷枯,看看登錄頁(yè)面滚秩,輸入下面數(shù)據(jù),查看是否登錄成功淮捆,成功就會(huì)進(jìn)入index.html頁(yè)面

shiro-09.png
shiro-10.png

回到代碼郁油,寫一個(gè)需要有權(quán)限才能訪問(wèn)的頁(yè)面本股,這里面的select在之前的yml文件中是已經(jīng)配置過(guò)的了。需要有查詢權(quán)限才能訪問(wèn)桐腌。代碼寫好重啟拄显,去網(wǎng)頁(yè)上訪問(wèn)

@ResponseBody
public Map<String, Object> getInfo() throws Exception {
    Map<String, Object> map = new HashMap<>();
    map.put("filterRule", reader.getFilterRuleMap());
    map.put("filterClass", reader.getFilterClassValue());
    map.put("loginUrl", reader.getLoginUrl());
    map.put("unauthorizedUrl", reader.getUnauthorizedUrl());
    map.put("successUrl", reader.getSuccessUrl());
    return map;
}

網(wǎng)頁(yè)輸入localhost:8052/select/info,執(zhí)行訪問(wèn)案站,由于已經(jīng)重啟躬审,多以他會(huì)跳轉(zhuǎn)到登錄頁(yè)面,這時(shí)候需要重新登錄蟆盐。(如果還是在首頁(yè)面承边,那就是網(wǎng)頁(yè)緩存的問(wèn)題,清一下就好)

如果出現(xiàn)一下的狀態(tài)石挂,就是沒(méi)問(wèn)題的

shiro-11.png

如果用戶沒(méi)用登錄炒刁,或者登錄了但是沒(méi)有這個(gè)查驗(yàn)的權(quán)利呢?用戶呢誊稚?

輸入localhost:8052/logout注銷登錄,再次輸入localhost:8052/select/info嘗試罗心。

沒(méi)登錄的用戶不能訪問(wèn)里伯,會(huì)跳轉(zhuǎn)到登錄頁(yè)面,而登錄的用戶渤闷,卻沒(méi)有這個(gè)權(quán)限的疾瓮,會(huì)跳轉(zhuǎn)到如下頁(yè)面,之后再跳轉(zhuǎn)到登錄頁(yè)面

shiro-12.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末飒箭,一起剝皮案震驚了整個(gè)濱河市狼电,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弦蹂,老刑警劉巖肩碟,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異凸椿,居然都是意外死亡削祈,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門脑漫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)髓抑,“玉大人,你說(shuō)我怎么就攤上這事优幸《峙模” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵网杆,是天一觀的道長(zhǎng)羹饰。 經(jīng)常有香客問(wèn)我伊滋,道長(zhǎng),這世上最難降的妖魔是什么严里? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任新啼,我火速辦了婚禮,結(jié)果婚禮上刹碾,老公的妹妹穿的比我還像新娘燥撞。我一直安慰自己,他們只是感情好迷帜,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布物舒。 她就那樣靜靜地躺著,像睡著了一般戏锹。 火紅的嫁衣襯著肌膚如雪冠胯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天锦针,我揣著相機(jī)與錄音荠察,去河邊找鬼。 笑死奈搜,一個(gè)胖子當(dāng)著我的面吹牛悉盆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播馋吗,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼焕盟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了宏粤?” 一聲冷哼從身側(cè)響起脚翘,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绍哎,沒(méi)想到半個(gè)月后来农,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛇摸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年备图,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赶袄。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡揽涮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出饿肺,到底是詐尸還是另有隱情蒋困,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布敬辣,位于F島的核電站雪标,受9級(jí)特大地震影響零院,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜村刨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一告抄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嵌牺,春花似錦打洼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至僻弹,卻和暖如春阿浓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹋绽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工芭毙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卸耘。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓稿蹲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鹊奖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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