shiro學(xué)習(xí)之集成 spring和登錄認(rèn)證

用 shiro 實(shí)現(xiàn)最基本的登錄認(rèn)證是一件非常簡(jiǎn)單的事情,我覺得官網(wǎng)給的例子不太好用,反正我是沒搞出來,現(xiàn)在寫一份自己的教程。


項(xiàng)目地址:https://github.com/thecattle/spring-mvc-shiro


目的

  • 集成 shiro 到 spring 上
  • 實(shí)現(xiàn)最基本的登錄認(rèn)證

項(xiàng)目環(huán)境

  • spring+spring-mvc
  • maven3
  • IntelliJ IDEA
  • jdk1.8

1. 添加 shiro 配置

1.1 修改 pom 文件

添加 shiro maven :

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

1.2 修改 web.xml 文件

 <!--shiro 配置-->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

1.3 為了項(xiàng)目結(jié)構(gòu)清晰,單獨(dú)新建 shiro 配置文件

在 resource 目錄新建 shiro.xml

image.png
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm">
            <!--自定義 MyRealm,登錄的認(rèn)證入口 ,需要繼承AuthorizingRealm,項(xiàng)目中會(huì)體現(xiàn)-->
            <bean class="com.sunp.shiro.MyRealm"></bean>
        </property>

    </bean>

    <!--shiro 請(qǐng)求攔截器,這里的 bean id 一定要對(duì)應(yīng) web.xml 中的filter-name,否則找不到這個(gè)攔截器-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"></property>
    </bean>

    <!-- 保證實(shí)現(xiàn)了Shiro內(nèi)部lifecycle函數(shù)的bean執(zhí)行 ,不明覺厲,沒有深究-->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

</beans>

1.4 修改 spring 配置文件 applicationContext.xml

將 shiro.xml導(dǎo)入到 spring 容器中

   <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--啟用spring的一些annotation -->
    <context:annotation-config/>

    <!--在 shiro 中用到了 UserService,shiro 是運(yùn)行在 spring 容器中的, shiro 和 spring-mvc 級(jí)別是平行的,
        所以 spring-mvc 的掃描不起作用,這里再掃描一次,所有的 bean 加載到 spring 容器中-->
    <context:component-scan base-package="com.sunp.**"></context:component-scan>
 
    <!--導(dǎo)入 shiro 配置-->
    <import resource="classpath:shiro.xml"></import>
</beans>

配置到這里就差不多了。

2. 添加 shiro 項(xiàng)目代碼

2.1 新建自定義的 realm

我這里創(chuàng)建在 com.sunp.shiro包下,對(duì)應(yīng) shiro.xml 中的配置。仔細(xì)看注釋

public class MyRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    /**
     * 認(rèn)證用戶的操作
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        //從假數(shù)據(jù)源中拿當(dāng)前用戶數(shù)據(jù)
        User userDao = userService.getUserInfo(token.getUsername());
        if (userDao==null){
            //扔出個(gè)異常,currentUser.login(token);可以 catch 到
            throw new UnknownAccountException("未知用戶");
        }

        //如果數(shù)據(jù)庫中存在這個(gè)用戶名
        if(userDao.getUserName().equals(token.getUsername())){
            //創(chuàng)建認(rèn)證對(duì)象,傳入數(shù)據(jù)庫存在的對(duì)象賬號(hào)和密碼,內(nèi)部會(huì)根據(jù) currentUser.login(token) 的 token 進(jìn)行比較
            AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(userDao.getUserName(), userDao.getUserPassword(), this.getName());
            return authcInfo;
        }
        return null;

    }

}

2.2 在 LoginController 中添加登錄方法

    //方便調(diào)試 直接用 get
    @RequestMapping(value = "/login",method = RequestMethod.GET)
    @ResponseBody
    public Map<String,Object> login(String username,String password){
        Map<String,Object> map=new HashMap<>();
        logger.info("開始登錄");
        //構(gòu)建登錄 token
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //設(shè)置記住我
        token.setRememberMe(true);
        //獲取當(dāng)前登錄用戶
        Subject currentUser = SecurityUtils.getSubject();
        try {
            //登錄
            currentUser.login(token);
            //判斷用戶狀態(tài)是否已經(jīng)被認(rèn)證
            if (currentUser.isAuthenticated()){
                map.put("msg","登錄成功");
            }else {
                map.put("msg","系統(tǒng)異常,請(qǐng)重試");
            }
        } catch (UnknownAccountException uae) {
            map.put("msg","未知用戶");
        } catch (IncorrectCredentialsException ice) {
            map.put("msg","認(rèn)證失敗");
        } catch (LockedAccountException lae) {
            map.put("msg","賬戶已鎖定");
        } catch (ExcessiveAttemptsException eae) {
            map.put("msg","登錄失敗次數(shù)過多");
        } catch (AuthenticationException ae) {
            map.put("msg",ae.getMessage());
        }
        return map;
    }

3. 項(xiàng)目結(jié)構(gòu)

最后的項(xiàng)目結(jié)構(gòu)如下:藍(lán)色為修改過文件,綠色為新增文件

image.png

4. 測(cè)試

4.1 假的數(shù)據(jù)源為:

image.png

4.2 測(cè)試正確

image.png

4.3 測(cè)試不存在的用戶

image.png

4.4 測(cè)試錯(cuò)誤的密碼

image.png

自學(xué)筆記,如有錯(cuò)誤,期待評(píng)論指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容