ssm配置完成shiro,实现登录验证的功能

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Honnyee/article/details/82663005

花了一天时间,算是完成了shiro登录验证的这一基本功能。

https://www.w3cschool.cn/shiro/andc1if0.html 这个教程可以多看看,核心的基础功能很重要。

实现shiro

第一步,引入所需要的依赖

在pom.xml文件中加入

<properties>

        <!-- log4j日志文件管理包版本 -->

        <slf4j.version>1.7.7</slf4j.version>

        <log4j.version>1.2.17</log4j.version>

    </properties>

        <!-- log start -->

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>${log4j.version}</version>

        </dependency>

        <!-- 格式化对象,方便输出日志 -->

        <dependency>

            <groupId>com.alibaba</groupId>

            <artifactId>fastjson</artifactId>

            <version>1.1.41</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-api</artifactId>

            <version>${slf4j.version}</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-log4j12</artifactId>

            <version>${slf4j.version}</version>

        </dependency>

        <!-- log end -->

        <!-- shiro -->

        <dependency>

            <groupId>org.apache.shiro</groupId>

            <artifactId>shiro-all</artifactId>

            <version>1.3.2</version>

        </dependency>

        <!-- ehcache -->

        <dependency>

            <groupId>net.sf.ehcache</groupId>

            <artifactId>ehcache-core</artifactId>

            <version>2.6.11</version>

        </dependency>


 

第二步:在web.xml中配置shiroFilter

  

<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>

第三步:新建类MyShiroRealm,代码里面有详细的注释

package com.wolwo.shiro;

public class MyShiroReaml extends AuthorizingRealm {

    @Autowired

    ShiroUserService shiroUserService;

    /**

     * Authorization(授权):访问控制的过程,即决定是否有权限去访问受保护的资源。

     * @param pc

     * @return

     */

    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {

        return null;

    }


    /**

     * Authentication(身份验证):简称为“登录”,即证明用户是谁。

     * @param token

     * @return

     * @throws AuthenticationException

     */

    @Override

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {


        // 1. 把AuthenticationToken转换为UsernamePasswordToken

        UsernamePasswordToken upToken = (UsernamePasswordToken) token;

        // 2. 从UsernamePasswordToken中获取email

        String staffId = upToken.getUsername();

        // 3. 若用户不存在,抛出UnknownAccountException异常

        ShiroUser shiroUser = shiroUserService.selectByStaffId(staffId);

        if (shiroUser == null) {

            throw new UnknownAccountException("用户不存在!");

        }

        // 4.

        // 根据用户的情况,来构建AuthenticationInfo对象并返回,通常使用的实现类为SimpleAuthenticationInfo

        // 以下信息从数据库中获取

        // (1)principal:认证的实体信息,可以是email,也可以是数据表对应的用户的实体类对象

        Object principal = staffId;

        // (2)credentials:密码

        Object credentials = shiroUser.getPassword();

        // (3)realmName:当前realm对象的name,调用父类的getName()方法即可

        String realmName = getName();

        // (4)盐值:取用户信息中唯一的字段来生成盐值,避免由于两个用户原始密码相同,加密后的密码也相同

        ByteSource credentialsSalt = ByteSource.Util.bytes(staffId);

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt,

                realmName);

        return info;

    }

}

 

第四步:在src目录下新建ehcache.xml


<?xml version="1.0" encoding="UTF-8"?>

<ehcache>

    <diskStore path="./target/tmp"/>

    <defaultCache

            maxElementsInMemory="10000"

            eternal="false"

            timeToIdleSeconds="120"

            timeToLiveSeconds="120"

            overflowToDisk="true"

    />

    <cache name="sampleCache1"

           maxElementsInMemory="10000"

           eternal="false"

           timeToIdleSeconds="300"

           timeToLiveSeconds="600"

           overflowToDisk="true"

    />

    <cache name="sampleCache2"

           maxElementsInMemory="1000"

           eternal="true"

           timeToIdleSeconds="0"

           timeToLiveSeconds="0"

           overflowToDisk="false"

    />

</ehcache>

 

第五步:在spring配置文件spring-shiro.xml 中配置shiro,随后在spring配置文件里import引入

<?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">

    <!-- shiro start -->
    <!-- 1. 配置SecurityManager -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager" />
        <property name="authenticator" ref="authenticator"></property>
        <!-- 可以配置多个Realm,其实会把realms属性赋值给ModularRealmAuthenticator的realms属性 -->
        <property name="realms">
            <list>
                <ref bean="userRealm" />
            </list>
        </property>
    </bean>

    <!-- 2. 配置CacheManager -->
    <!-- 2.1 需要加入ehcache的jar包及配置文件 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
    </bean>

    <!-- 3. 配置Realm -->
    <!-- 3.1 直接配置继承了org.apache.shiro.realm.AuthorizingRealm的bean -->
    <bean id="userRealm" class="com.wolwo.shiro.MyShiroReaml">
        <!-- 配置密码匹配器 -->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!-- 加密算法为MD5 -->
                <property name="hashAlgorithmName" value="MD5"></property>
                <!-- 加密次数 -->
                <property name="hashIterations" value="2"></property>
            </bean>
        </property>
    </bean>

    <!-- 4. 配置LifecycleBeanPostProcessor,可以自定义地来调用配置在Spring IOC容器中shiro bean的生命周期方法 -->
    <!--<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />-->

    <!-- 5. 使能够在IOC容器中使用shiro的注解,但必须在配置了LifecycleBeanPostProcessor之后才可以使用 -->
    <!--<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>-->

    <!-- 6. 配置ShiroFilter -->
    <!-- 6.1 id必须和web.xml中配置的DelegatingFilterProxy的<filter-name>一致。 如果不一致,会抛出NoSuchBeanDefinitionException异常,因为shiro会在IOC容器中查找名称和<filter-name>
        值一致的filter bean -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager" />
        <!--<property name="loginUrl" value="/login.jsp" />-->
        <!--<property name="successUrl" value="/WEB-INF/user/index.jsp" />-->
        <!--<property name="unauthorizedUrl" value="/login.jsp" />-->
        <!-- 配置哪些页面需要受保护,以及访问这些页面需要的权限 -->
        <!--<property name="filterChainDefinitions">-->
            <!--<value>-->
                <!--&lt;!&ndash; 第一次匹配优先的原则 &ndash;&gt;-->
                <!--/login.jsp = anon-->
                <!--/user/login = anon-->

                <!--/logout = logout-->

                <!--/** = authc-->
            <!--</value>-->
        <!--</property>-->
    </bean>

    <!-- 7. 配置ModularRealmAuthenticator,可以实现多Realm认证 -->
    <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
        <!-- 配置认证策略,只要有一个Realm认证成功即可,并且返回所有认证成功信息 -->
        <property name="authenticationStrategy">
            <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
        </property>
    </bean>
    <!-- shiro end -->
</beans>

 

里面有很多被我注释起来了,是因为在测试的过程中,出现过很多错误,这些错误设计到权限、角色、还有shiro的一些其他功能。因为在学习中,尽量简化开发,而且目前只需要登录验证的功能,所以选择注释了起来。

但是有一个很严重的问题,我是用idea开发的,现在我项目的tomcat可以启动,但是启动后用redeplod或者restart server都会报错,只有关掉tomcat后,再启动才能运行,我怀疑是eccache的问题,但是还没有找到解决方案

第六步:测试(包括controller、servicemapper等

service和mapper等在此省略

我新建了一个表专门用于shiro的用户登录

 

然后生成了service,mapper文件,写了一个 用staffId查询信息的方法。

在controller里的写法

package com.wolwo.shiro.controller;

import com.wolwo.system.domain.ShiroUser;
import com.wolwo.system.service.ShiroUserService;
import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpSession;
import java.util.Date;
import java.util.Map;


@Controller
@RequestMapping("/user")
public class ShiroController {
    @Autowired
    ShiroUserService shiroUserService;

    @RequestMapping(value = "register", method = RequestMethod.POST)
    public void register(
//            @RequestParam("staffId") String staffId, @RequestParam("password") String password
            @RequestBody Map<String,String> map
    ) {
        String staffId = map.get("staffId");
        String password = map.get("password");
        String passwordMd5 = new SimpleHash("md5", password, staffId, 2).toString();
        ShiroUser shiroUser = new ShiroUser();
        shiroUser.setStaffId(staffId);
        shiroUser.setPassword(passwordMd5);
        shiroUser.setCreateTime(new Date());
        shiroUserService.insertSelective(shiroUser);
    }

    @RequestMapping(value = "login", method = RequestMethod.POST)
    public void login(
//            @RequestParam("staffId") String staffId, @RequestParam("password") String password
            @RequestBody Map<String,String> map
    ) {
        String staffId = map.get("staffId");
        String password = map.get("password");
        Subject subject = SecurityUtils.getSubject();
        if (!subject.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(staffId, password);
            token.setRememberMe(false);
            try {
                subject.login(token);
                System.out.println("登录成功");
            } catch (IncorrectCredentialsException ice) {
                System.out.println("邮箱/密码不匹配!");
            } catch (LockedAccountException lae) {
                System.out.println("账户已被冻结!");
            } catch (AuthenticationException ae) {
                System.out.println("token生成异常" + ae.getMessage());
            }
        }
    }

}

       有一点需要注意的是,controller中注册的接口加密方式,与shiro的密码加密方式保持一致才能使用,否则出现密码不正确、生成token失败等问题。

这些写完后,可以先使用注册和登录接口,测试是否可用,我是可用的。

猜你喜欢

转载自blog.csdn.net/Honnyee/article/details/82663005