SSM プロジェクトで shiro を使用する方法 [詳細なチュートリアル]

序文

Shiro は、強力で使いやすい Java セキュリティ フレームワークです。Web プロジェクトでは、shiro をログイン セキュリティ検証に使用できます. SSM プロジェクトで shiro を使用する方法を紹介します: ページ インターセプト、カスタム レルム、MD5 暗号化ログイン検証 (パスワード、ロール検証)


1.SSM プロジェクトを作成する

開発ツール: IDEA2022
フレームワーク バージョン: Spring5.1.19
Mybaits3.5.6

1. 依存

私が使用する依存関係 (ssm shiro) を参照してください。

<dependencies>
        <!-- 添加Servlet支持 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>

        <!-- JSP -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
        </dependency>

        <!-- 添加jstl支持 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <!-- 添加Spring支持 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.19.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- 添加日志支持 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>

        <!-- 添加mybatis支持 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <!-- jdbc驱动包  -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.37</version>
        </dependency>

        <!-- 添加shiro支持 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.7.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>1.7.0</version>
        </dependency>

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

        <!-- apache公共包 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.5</version>
        </dependency>

        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.8.0</version>
        </dependency>

        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>net.sf.ezmorph</groupId>
            <artifactId>ezmorph</artifactId>
            <version>1.0.6</version>
        </dependency>

        <!-- 添加连接池druid支持 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.14</version>
        </dependency>

    </dependencies>

2.ファイルディレクトリ

ここに画像の説明を挿入

  1. controller: 特定のビジネス プロセスを制御します。リクエストの転送とフロントエンドからのパラメーターの受け入れを担当します。
  2. dao: データベースに対して直接データ操作を実行します。テーブルに対する操作の追加、削除、変更、およびクエリ。
  3. エンティティ: エンティティ クラス。
  4. realm: カスタム レルムを格納します。
  5. service: 特定のビジネス ロジックに従って Dao レイヤーの操作をカプセル化し、サービス インターフェイスとサービス実装クラスを格納します。
  6. util: ツール クラスを保存します。ここでは MD5 ツール クラスを保存します

3. 設定ファイル

(1) コンテキスト (applicationContent.xml)

shiro 構成、カスタム レルム、セキュリティ マネージャーを含み、shiro の内部ライフサイクル関数、shiro インターセプター、shiro アノテーションの Bean 実行を保証します

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <!-- 自动扫描 -->
    <context:component-scan base-package="service"/>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="jdbc:mysql://localhost:13306/db_sms?useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="abc456"/>
    </bean>

    <!-- 配置mybatis的sqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 自动扫描mappers.xml文件 -->
        <property name="mapperLocations" value="classpath:mappers/*.xml"/>
        <!-- mybatis配置文件 -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 自定义Realm -->
    <bean id="myRealm" class="realm.MyRealm"/>

    <!-- 安全管理器-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
    </bean>

    <!-- Shiro过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全接口,这个属性是必须的 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份认证失败,则跳转到登录页面的配置 -->
        <property name="loginUrl" value="/login.jsp"/>
        <!-- Shiro连接约束配置,即过滤链的定义 -->
        <property name="filterChainDefinitions">
            <value>
                /login=anon
                /*=authc
            </value>
        </property>
    </bean>

    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 开启Shiro注解 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

    <!-- 配置事务通知属性 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 定义事务传播属性 -->
        <tx:attributes>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="edit*" propagation="REQUIRED"/>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="add*" propagation="REQUIRED"/>
            <tx:method name="new*" propagation="REQUIRED"/>
            <tx:method name="set*" propagation="REQUIRED"/>
            <tx:method name="remove*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="change*" propagation="REQUIRED"/>
            <tx:method name="check*" propagation="REQUIRED"/>
            <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="load*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!-- 配置事务切面 -->
    <aop:config>
        <aop:pointcut id="serviceOperation"
                      expression="execution(* service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
    </aop:config>
</beans>

(2) ログ (log4j.properties)

log4j.rootLogger=DEBUG, Console
  
#Console  
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
  
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

(3)Mybatis配置(mybatis-config.xml)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 别名 -->
    <typeAliases>
        <package name="entity"/>
    </typeAliases>
</configuration>

(4) スプリング構成 (spring-mvc.xml)

<?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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
        http://www.springframework.org/schema/mvc   http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd  
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd  
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <mvc:annotation-driven/>

    <mvc:resources mapping="/static/**" location="/static/"/>

    <!-- 视图解析器 -->
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="maxUploadSize" value="10000000"/>
    </bean>

    <!-- 使用注解的包,包括子集 -->
    <context:component-scan base-package="controller"/>
</beans>  

2.基本ページ

ランダムなコンテンツを含む login.jsp ファイルと success.jsp ファイルを作成します。デモンストレーションの便宜上、ここではスタイルを追加せず、単純なページ要素のみを追加します。

ログインページ:

<form action="${pageContext.request.contextPath}/user/login.do" method="post">
        <label for="userName">用户名:</label><input type="text" id="userName" name="userName">
        <label for="password">密码:</label><input type="password" id="password" name="password">
        <input type="submit" value="登录"><label style="color: red">${errorInfo}</label>
    </form>

注: input タグの name 属性は、input 要素の名前を指定します。サーバーに送信されたフォームデータを識別したり、クライアント側で JavaScript を介してフォームデータを参照したりするために使用されます。name 属性が設定されたフォーム要素のみが、フォームの送信時に値を渡します。(設定する必要があります)

成功ページ:

<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>成功</h1>
</body>
</html>

3. ページ傍受

上記のコンテキスト構成ファイル (applicationContent) では、shiro インターセプターの構成に注意してください。

    <!-- Shiro过滤器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login.jsp"/>
        <!-- Shiro连接约束配置,即过滤链的定义 -->
        <property name="filterChainDefinitions">
            <value>
                /login=anon
                /*=authc
            </value>
        </property>
    </bean>
  1. securityManager: Shiro のコア セキュリティ インターフェイスを構成する必要があります。
  2. loginUrl: 認証に失敗しました。ログイン ページにジャンプします。
  3. filterChainDefinitions: 制約チェーンを構成する場合、anon はアクセスを許可し、authc はアクセスを許可しないことに注意してください. ここでは、ログイン ページにアクセスするときに、/login=anon へのアクセスを許可し、他のページへのアクセスを許可しないことを定義します。 /*=認証。

デモ GIF では
ここに画像の説明を挿入
、ログイン ページには正常にアクセスできますが、成功ページにはアクセスできないことがわかります。

4.レルムをカスタマイズする

権限管理を行う場合、ユーザーのアカウントパスワードが正しいかどうかを判断する認証と、ユーザーがログイン後にどのような権限を持っているかを判断する認可とに分けられます。認証機能のデモンストレーションを次に示します。Realm
ディレクトリに MyRealm クラスを作成して AuthorizingRealm クラスを継承します。AuthorizationInfo と AuthenticationInfo の 2 つのメソッドがあります。

AuthorizationInfo は、現在のユーザーに役割と権限を付与します
AuthenticationInfo は、現在ログインしているユーザーを検証します

認証機能を実行するには、
次のように AuthenticationInfo コードを使用するだけです。

package realm;

import entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import service.UserService;

import javax.annotation.Resource;

public class MyRealm extends AuthorizingRealm {
    
    

    @Resource
    private UserService userService;

    //为当前的用户授予角色和权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
        return null;
    }

    //验证当前的登录的用户
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
    
        String userName = (String) token.getPrincipal();
        User user = userService.getByUserNme(userName);
        if (user!=null){
    
    
            SecurityUtils.getSubject().getSession().setAttribute("currentUser",user);//当前用户存到session中
            AuthenticationInfo authInfo = new SimpleAuthenticationInfo(user.getUserName(), user.getPassword(), "xxx");
            return authInfo;
        }else {
    
    
            return null;
        }
    }
}

5. ビジネスロジック

(1) daoインターフェース方式、サービスインターフェース方式

public User getByUserNme(String userName);

(2) Mapper方式

<?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="dao.UserDao">
    <resultMap type="User" id="UserResult">
        <result property="id" column="id"/>
        <result property="userName" column="userName"/>
        <result property="password" column="password"/>
        <result property="role" column="role"/>
    </resultMap>

    <select id="getByUserNme" parameterType="string" resultMap="UserResult">
        select *
        from t_user
        where userName = #{userName};
    </select>

</mapper>

(3) serviceImpl 実装クラス

package service.impl;

import dao.UserDao;
import entity.User;
import org.springframework.stereotype.Service;
import service.UserService;

import javax.annotation.Resource;

@Service("userService")
public class UserServiceImpl implements UserService {
    
    
    @Resource
    private UserDao userDao;

    @Override
    public User getByUserNme(String userName) {
    
    
        return userDao.getByUserNme(userName);
    }
}

(4) コントローラ方式

上記の内容を準備したら、コントローラーのフロントエンド ロジックを記述できます。

package controller;

import entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import service.UserService;
import util.CryptographyUtil;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("/user")
public class UserController {
    
    
    @Resource
    private UserService userService;

    //管理系统登录验证
    @RequestMapping("/login")
    public String login(User user, HttpServletRequest request) {
    
    
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), CryptographyUtil.md5(user.getPassword(),"leo"));
        try {
    
    
            subject.login(token);//登录验证
            return "redirect:/success.jsp";
        } catch (Exception e) {
    
    
            e.printStackTrace();
            request.setAttribute("user", user);
            request.setAttribute("errorInfo", "用户名或者密码错误!");
            return "login";
        }
    }
}

6.効果のデモンストレーション

成功効果

ここに画像の説明を挿入
ここに画像の説明を挿入

失敗効果

ここに画像の説明を挿入


終了

以上が本記事の全文です。
何か問題がある場合は、指摘してください。議論を歓迎します。ははは

おすすめ

転載: blog.csdn.net/m0_59420288/article/details/127594442