springboot整合shiro(含MD5加密)

寫在前面:

關于shiro介紹以及shiro整合spring,我在另一篇文章中已詳細介紹彬碱,此處不作說明,請參考spring整合shiro奥洼。下載源碼巷疼。


歡迎大家關注我的公眾號 javawebkf,目前正在慢慢地將簡書文章搬到公眾號灵奖,以后簡書和公眾號文章將同步更新嚼沿,且簡書上的付費文章在公眾號上將免費。


開發(fā)環(huán)境:

1瓷患、mysql - 5.7.21
2骡尽、navicat(mysql客戶端管理工具)
3、idea 2017
4尉尾、jdk9
5爆阶、tomcat 8.5
6、springboot
7沙咏、mybatis 3
8辨图、shiro
9、maven

項目開始:

一肢藐、數(shù)據(jù)庫設計:

注:數(shù)據(jù)庫三張表和spring整合shiro中的一模一樣故河,在那邊已經(jīng)詳細說明,這里直接大家看下三張表的ER圖吆豹。

圖片發(fā)自簡書App

二鱼的、添加依賴,配置mybatis

1痘煤、用idea新建Spring Initializr項目凑阶,項目結(jié)構如下:

圖片發(fā)自簡書App

2、添加依賴:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.20</version>
        </dependency>
        <!--常用的工具包-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
        <!--spring的上下文工具包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.1.7.RELEASE</version>
        </dependency>
        <!--對jsp的處理-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>
    </dependencies>

3衷快、application.properties

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql:///#
spring.datasource.username=#
spring.datasource.password=#
## mybatis ##
mybatis.mapper-locations=mappers/*.xml
mybatis.type-aliases-package=com.zhu.shiro.entity
## 視圖解析器 ##
spring.mvc.view.prefix=/pages/
spring.mvc.view.suffix=.jsp

三宙橱、項目設計

注:spring整合shiro中是只有User實體類,在UserDao中定義了三個方法蘸拔,通過表的關鍵關系查詢Role和Permission;這里將采用另一種方式师郑,三個實體類,設置實體類的關聯(lián)關系调窍。
1宝冕、entity層
User.java

public class User {

    private  Integer uid;
    private  String username;
    private  String password;
    private  Set<Role> roles = new HashSet<>();
}

Role.java

public class Role {

    private  Integer rid;
    private  String name;
    private  Set<Permission> permissions = new HashSet<>();
}

Permission.java

public class Permission {
    private  Integer pid;
    private  String  name;
}

2、dao層
UserDao.java

public interface UserDao {
    User findByUsername(String username);
}

UserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhu.shiro.dao.UserDao">

    <resultMap id="userMap" type="com.zhu.shiro.entity.User">
        <id property="uid" column="uid"/>
        <result property="username" column="user_name"/>
        <result property="password" column="pass_word"/>
        <collection property="roles" ofType="com.zhu.shiro.entity.Role">
            <id property="rid" column="rid"/>
            <result property="name" column="role_name"/>
            <collection property="permissions" ofType="com.zhu.shiro.entity.Permission">
                <id property="pid" column="pid"/>
                <result property="name" column="permission_name"/>
            </collection>
        </collection>
    </resultMap>

    <select id="findByUsername" parameterType="string" resultMap="userMap">
           SELECT *
           FROM tb_user u,tb_role r,tb_permission p
           WHERE u.rid=r.rid
           AND p.rid=r.rid
           AND u.user_name=#{username}
    </select>
    
</mapper>

3邓萨、service層

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;
    @Override
    public User findByUsername(String username) {
        return userDao.findByUsername(username);
    }
}

4地梨、junit測試

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceImplTest {
    @Autowired
    private UserService userService;
    @Test
    public void findByUsername() {
        User u = userService.findByUsername("tom");
        Set<Role> roleSet = u.getRoles();
        for (Role role : roleSet){
            Set<Permission> permissionSet = role.getPermissions();
            for (Permission permission : permissionSet){
                System.out.println(permission.getName());
            }
            System.out.println(role.getName());
        }
    }
}

運行結(jié)果:

圖片發(fā)自簡書App

數(shù)據(jù)庫中tom是admin角色菊卷,有增刪改查權限,符合預期湿刽,測試通過的烁。

5、controller層
TestController.java

@Controller
public class TestController {

    //用戶登錄
    @RequestMapping("/loginUser")
    public String loginUser(@RequestParam("username") String username,
                            @RequestParam("password") String password,
                            HttpSession session) {
        //把前端輸入的username和password封裝為token
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            session.setAttribute("user", subject.getPrincipal());
            return "index";
        } catch (Exception e) {
            return "login";
        }
    }

    //退出登錄
    @RequestMapping("/logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        if (subject != null) {
            subject.logout();
        }
        return "login";
    }

    //訪問login時跳到login.jsp
    @RequestMapping("/login")
    public String login() {
        return "login";
    }

    //admin角色才能訪問
    @RequestMapping("/admin")
    @ResponseBody
    public String admin() {
        return "admin success";
    }

    //有delete權限才能訪問
    @RequestMapping("/edit")
    @ResponseBody
    public String edit() {
        return "edit success";
    }

    @RequestMapping("/test")
    @ResponseBody
    @RequiresRoles("guest")
    public String test(){
        return "test success";
    }

}

說明:這里用戶登錄方法用到了shiro诈闺,但是這里還沒配置shiro渴庆,所以暫時不能使用,先搭起整個骨架雅镊,然后再加入shiro襟雷。

6、jsp頁面
login.jsp
(登錄頁面)

%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Login</title>
</head>
<body>
   <h1>歡迎登錄仁烹!</h1>
   <form action="/loginUser" method="post">
       <input type="text" name="username"><br>
       <input type="password" name="password"><br>
       <input type="submit" value="提交">
   </form>

</body>
</html>

index.jsp
(登錄成功跳轉(zhuǎn)的頁面)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
   <h1>歡迎登錄耸弄,${user.username}</h1>
</body>
</html>

unauthorized.jsp
(無權訪問跳轉(zhuǎn)的頁面)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>unauthorized</title>
</head>
<body>

unauthorized!
</body>
</html>

現(xiàn)在說一下要求:
admin路由要求只有具有admin角色的用戶才能訪問,edit路由需要有delete權限的用戶才能訪問卓缰,test路由要guest角色才能訪問计呈,login、loginUser都不做攔截征唬,本文講解兩種攔截方式捌显,對test的攔截是在controller對應的方法上加注解,其他是攔截是寫在shiro的配置類中总寒。
預期分析:
tom是有admin角色和所有權限扶歪,所以用tom登錄后,可以訪問edit和admin摄闸,但是不能訪問guest;而cat是guest角色善镰,只有create和query權限,所以不能訪問admin和edit年枕,但是可以訪問guest炫欺。

四、配置shiro

由于springboot還沒有集成shiro熏兄,所以不能直接在application.properties中配置竣稽,需要通過類的方式配置。

核心配置類:

ShiroConfiguration.java

@Configuration
public class ShiroConfiguration {
    /**
     * 密碼校驗規(guī)則HashedCredentialsMatcher
     * 這個類是為了對密碼進行編碼的 ,
     * 防止密碼在數(shù)據(jù)庫里明碼保存 , 當然在登陸認證的時候 ,
     * 這個類也負責對form里輸入的密碼進行編碼
     * 處理認證匹配處理器:如果自定義需要實現(xiàn)繼承HashedCredentialsMatcher
     */
    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //指定加密方式為MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //加密次數(shù)
        credentialsMatcher.setHashIterations(1024);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher;
    }


    @Bean("authRealm")
    @DependsOn("lifecycleBeanPostProcessor")//可選
    public AuthRealm authRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
        AuthRealm authRealm = new AuthRealm();
        authRealm.setAuthorizationCachingEnabled(false);
        authRealm.setCredentialsMatcher(matcher);
        return authRealm;
    }


    /**
     * 定義安全管理器securityManager,注入自定義的realm
     * @param authRealm
     * @return
     */
    @Bean("securityManager")
    public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(authRealm);
        return manager;
    }


    /**
     * 定義shiroFilter過濾器并注入securityManager
     * @param manager
     * @return
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //設置securityManager
        bean.setSecurityManager(manager);
        //設置登錄頁面
        //可以寫路由也可以寫jsp頁面的訪問路徑
        bean.setLoginUrl("/login");
        //設置登錄成功跳轉(zhuǎn)的頁面
        bean.setSuccessUrl("/pages/index.jsp");
        //設置未授權跳轉(zhuǎn)的頁面
        bean.setUnauthorizedUrl("/pages/unauthorized.jsp");
        //定義過濾器
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/index", "authc");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/loginUser", "anon");
        filterChainDefinitionMap.put("/admin", "roles[admin]");
        filterChainDefinitionMap.put("/edit", "perms[delete]");
        filterChainDefinitionMap.put("/druid/**", "anon");
        //需要登錄訪問的資源 , 一般將/**放在最下邊
        filterChainDefinitionMap.put("/**", "authc");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

    /**
     * Spring的一個bean , 由Advisor決定對哪些類的方法進行AOP代理 .
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    /**
     * 配置shiro跟spring的關聯(lián)
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * lifecycleBeanPostProcessor是負責生命周期的 , 初始化和銷毀的類
     * (可選)
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

}

注:這個類每個bean的作用都已在代碼中注釋說明霍弹,這個類就相當于spring整合shiro的spring-shiro.xml中對shiro的配置。

自定義realm:

AutuRealm.java

public class AuthRealm extends AuthorizingRealm{
    @Autowired
    private UserService userService;
    /**
     * 為用戶授權
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //獲取前端輸入的用戶信息娃弓,封裝為User對象
        User userweb = (User) principals.getPrimaryPrincipal();
        //獲取前端輸入的用戶名
        String username = userweb.getUsername();
        //根據(jù)前端輸入的用戶名查詢數(shù)據(jù)庫中對應的記錄
        User user = userService.findByUsername(username);
        //如果數(shù)據(jù)庫中有該用戶名對應的記錄典格,就進行授權操作
        if (user != null){
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //因為addRoles和addStringPermissions方法需要的參數(shù)類型是Collection
            //所以先創(chuàng)建兩個collection集合
            Collection<String> rolesCollection = new HashSet<String>();
            Collection<String> perStringCollection = new HashSet<String>();
            //獲取user的Role的set集合
            Set<Role> roles = user.getRoles();
            //遍歷集合
            for (Role role : roles){
                //將每一個role的name裝進collection集合
                rolesCollection.add(role.getName());
                //獲取每一個Role的permission的set集合
                Set<Permission> permissionSet =  role.getPermissions();
                //遍歷集合
                for (Permission permission : permissionSet){
                    //將每一個permission的name裝進collection集合
                    perStringCollection.add(permission.getName());
                }
                //為用戶授權
                info.addStringPermissions(perStringCollection);
            }
            //為用戶授予角色
            info.addRoles(rolesCollection);
            return info;
        }else{
            return null;
        }

    }



    /**
     * 認證登錄
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //token攜帶了用戶信息
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        //獲取前端輸入的用戶名
        String userName  = usernamePasswordToken.getUsername();
        //根據(jù)用戶名查詢數(shù)據(jù)庫中對應的記錄
        User user = userService.findByUsername(userName);
        //當前realm對象的name
        String realmName = getName();
        //鹽值
        ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());
        //封裝用戶信息,構建AuthenticationInfo對象并返回
        AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user, user.getPassword(),
                credentialsSalt, realmName);
        return authcInfo;
    }
}

注:這個類也有詳細的注釋說明台丛。
這樣就完成了springboot對shiro的整合耍缴,接下來就可以進行測試了砾肺!

五、測試

tom登錄


圖片發(fā)自簡書App
圖片發(fā)自簡書App

tom訪問admin


圖片發(fā)自簡書App

tom訪問test


圖片發(fā)自簡書App

cat登錄


圖片發(fā)自簡書App

cat訪問admin


圖片發(fā)自簡書App

cat訪問test


圖片發(fā)自簡書App

測試結(jié)果與預期相符防嗡,測試通過变汪,springboot整合shiro成功!

特別說明:

由于設置了MD5加密,所以數(shù)據(jù)庫中存儲的用戶密碼應該是加密后的密文,否則在登錄頁面輸入明文會驗證不通過缴守。假如1234的密文為asdfghjkl佛舱,數(shù)據(jù)庫中存儲的應該是asdfghjkl,在登錄時輸入1234就能驗證通過出皇。
附上明文轉(zhuǎn)密文的代碼:

public static void main(String[] args) {
        String hashAlgorithName = "MD5";
        String password = "登錄時輸入的密碼";
        int hashIterations = 1024;//加密次數(shù)
        ByteSource credentialsSalt = ByteSource.Util.bytes("登錄時輸入的用戶名");
        Object obj = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);
        System.out.println(obj);
    }

若不使用MD5加密

1、添加一個類

public class CredenttiaMatcher extends SimpleCredentialsMatcher{
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String password = new String(usernamePasswordToken.getPassword());
        String dbPassword = (String) info.getCredentials();
        return this.equals(password,dbPassword);
    }
}

2、將ShiroConfiguration.java中名為"hashedCredentialsMatcher"的bean替換成:

*@Bean("credenttiaMatcher")
    public CredenttiaMatcher credenttiaMatcher() {
        return new CredenttiaMatcher();
    }

將名為"authRealm"的bean替換成:

@Bean("authRealm")
    @DependsOn("lifecycleBeanPostProcessor")//可選
    public AuthRealm authRealm(@Qualifier("credenttiaMatcher") CredenttiaMatcher matcher) {
        AuthRealm authRealm = new AuthRealm();
        authRealm.setCredentialsMatcher(matcher);
        return authRealm;
    }

3徘熔、AuthRealm.java中的doGetAuthenticationInfo方法里面的內(nèi)容替換成:

//=========================未加密版==========================
        //token攜帶了用戶登錄的信息
         UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        //獲取前端輸入的用戶名
        String username  = usernamePasswordToken.getUsername();
        //根據(jù)前端輸入的用戶名查詢數(shù)據(jù)庫中的記錄
         User user = userService.findByUsername(username);
        //校驗密碼,驗證登錄
         return new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName());

完成以上3步就去掉了MD5加密淆党。

以上內(nèi)容屬于個人學習筆記整理酷师,如有錯誤,歡迎批評指正染乌!

我的博客即將搬運同步至騰訊云+社區(qū)山孔,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=enfrqdpybh7v

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市慕匠,隨后出現(xiàn)的幾起案子饱须,更是在濱河造成了極大的恐慌,老刑警劉巖台谊,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蓉媳,死亡現(xiàn)場離奇詭異,居然都是意外死亡锅铅,警方通過查閱死者的電腦和手機酪呻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盐须,“玉大人玩荠,你說我怎么就攤上這事≡舻耍” “怎么了阶冈?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長塑径。 經(jīng)常有香客問我女坑,道長,這世上最難降的妖魔是什么统舀? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任匆骗,我火速辦了婚禮劳景,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碉就。我一直安慰自己盟广,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布瓮钥。 她就那樣靜靜地躺著筋量,像睡著了一般。 火紅的嫁衣襯著肌膚如雪骏庸。 梳的紋絲不亂的頭發(fā)上毛甲,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音具被,去河邊找鬼玻募。 笑死,一個胖子當著我的面吹牛一姿,可吹牛的內(nèi)容都是我干的七咧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼叮叹,長吁一口氣:“原來是場噩夢啊……” “哼艾栋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蛉顽,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蝗砾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后携冤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悼粮,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年曾棕,在試婚紗的時候發(fā)現(xiàn)自己被綠了扣猫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡翘地,死狀恐怖申尤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衙耕,我是刑警寧澤昧穿,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站橙喘,受9級特大地震影響时鸵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渴杆,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一寥枝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧磁奖,春花似錦囊拜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至身诺,卻和暖如春蜜托,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背霉赡。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工橄务, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人穴亏。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓蜂挪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嗓化。 傳聞我的和親對象是個殘疾皇子棠涮,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

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

  • shiro簡介: shiro是apache提供的一個強大易用的Java安全框架,用于身份驗證刺覆、授權严肪、密碼學和會話管...
    貪挽懶月閱讀 4,339評論 5 7
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn)谦屑,斷路器驳糯,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • 一充蓝、導語 今天推薦給大家一個非常簡單隧枫,實用的開源權限框架:Shiro,這也是Java官方推薦的權限框架谓苟。 盡管網(wǎng)上...
    宇哥聊AI閱讀 3,718評論 4 68
  • 青春就像一棵樹官脓,我們的人生延著不同的枝椏開花結(jié)果長大,短暫的互相觸碰后死去涝焙,留下一道悲涼的風景卑笨。
    愛秀秀太好了閱讀 206評論 2 1
  • 平安夜,美國11:30pm 星巴克里人氣比平時更旺仑撞,但是在駐足的人比往常更少赤兴,都是幾個人挽手進來妖滔,再高高興興地捧著...
    愛花的丫頭閱讀 335評論 0 1