在SSM中使用shiro实现登录验证(附密码加密)

  第一步:导入需要的jar:(maven方式)

    <properties>
        
        <slf4j.version>1.7.7slf4j.version>
        <log4j.version>1.2.17log4j.version>
    properties>

        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>${log4j.version}version>
        dependency>


        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>1.1.41version>
        dependency>


        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-apiartifactId>
            <version>${slf4j.version}version>
        dependency>

        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>${slf4j.version}version>
        dependency>
        

        
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-allartifactId>
            <version>1.3.2version>
        dependency>

        
        <dependency>
            <groupId>net.sf.ehcachegroupId>
            <artifactId>ehcache-coreartifactId>
            <version>2.6.11version>
        dependency>

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

   
    <filter>
        <filter-name>shiroFilterfilter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
        <init-param>
            <param-name>targetFilterLifecycleparam-name>
            <param-value>trueparam-value>
        init-param>
    filter>

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

  第三步:新建类UserRealm

package com.ang.elearning.shiro;

import javax.annotation.Resource;


import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import com.ang.elearning.po.User;
import com.ang.elearning.service.IUserService;

public class UserRealm extends AuthorizingRealm {

    @Resource
    IUserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        User user = null;
        // 1. 把AuthenticationToken转换为UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        // 2. 从UsernamePasswordToken中获取email
        String email = upToken.getUsername();
        // 3. 若用户不存在,抛出UnknownAccountException异常
        user = userService.getUserByEmail(email);
        if (user == null)
            throw new UnknownAccountException("用户不存在!");
        // 4.
        // 根据用户的情况,来构建AuthenticationInfo对象并返回,通常使用的实现类为SimpleAuthenticationInfo
        // 以下信息从数据库中获取
        // (1)principal:认证的实体信息,可以是email,也可以是数据表对应的用户的实体类对象
        Object principal = email;
        // (2)credentials:密码
        Object credentials = user.getPassword();
        // (3)realmName:当前realm对象的name,调用父类的getName()方法即可
        String realmName = getName();
        // (4)盐值:取用户信息中唯一的字段来生成盐值,避免由于两个用户原始密码相同,加密后的密码也相同
        ByteSource credentialsSalt = ByteSource.Util.bytes(email);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt,
                realmName);
        return info;
    }

}

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


<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配置文件中配置shiro

    
    
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager" />
        <property name="authenticator" ref="authenticator">property>
        
        <property name="realms">
            <list>
                <ref bean="userRealm" />
            list>
        property>
    bean>

    
    
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
    bean>

    
    
    <bean id="userRealm" class="com.ang.elearning.shiro.UserRealm">
        
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                
                <property name="hashAlgorithmName" value="MD5">property>
                
                <property name="hashIterations" value="1024">property>
            bean>
        property>
    bean>

    
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.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>

    
    
    <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>
                
                /login.jsp = anon
                /user/login = anon

                /logout = logout

                /** = authc
            value>
        property>
    bean>

    
    <bean id="authenticator" class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
        
        <property name="authenticationStrategy">
            <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy">bean>
        property>
    bean>
    

  第六步:测试(Userservice,UserDAO等略)
  
  UserController:

@Controller
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @RequestMapping(value = "login", method = RequestMethod.POST)
    public String login(@RequestParam("email") String email, @RequestParam("password") String password) {
        Subject currentUser = SecurityUtils.getSubject();
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken upToken = new UsernamePasswordToken(email, password);
            upToken.setRememberMe(false);
            try {
                currentUser.login(upToken);
                return "user/index";
            } catch (IncorrectCredentialsException ice) {
                System.out.println("邮箱/密码不匹配!");
            } catch (LockedAccountException lae) {
                System.out.println("账户已被冻结!");
            } catch (AuthenticationException ae) {
                System.out.println(ae.getMessage());
            }
        }
        return "redirect:/login.jsp";
    }
}

login.jsp:

<form action="${pageContext.request.contextPath }/user/login" method="POST">
        邮箱:<input type="text" name="email"> 
        <br><br>
        密码:<input type="password" name="password"> 
        <br><br>
        <input type="submit" value="登录">
    form>

/WEB-INF/user/index.jsp

<h4>Login Successfully!h4>
<br>
<a href="${pageContext.request.contextPath }/logout">Logouta>

补充:
shiro中默认的过滤器:

在SSM中使用shiro实现登录验证(附密码加密)_第1张图片

整个认证流程:
(1). 在Controller中通过Security.getSubject()获取当前的Subject;
(2). 通过Subject的isAuthenticated()验证当前用户是否已经被认证;
(3). 如果没有被认证,开始认证。
(4). 将从前台传来的用户名(邮箱)和密码封装到一个UsernamePasswordToken对象upToken中;
(5). 调用当前Subject的login(upToken)方法,这会把upToken作为参数传递到自定义的Realm的doGetAuthenticationInfo(AuthenticationToken)方法中;
(6). 在doGetAuthenticationInfo(AuthenticationToken)方法中,首先将AuthenticationToken转换为UsernamePasswordToken对象upToken,然后调用Service层,根据upToken中的用户名到数据库中查询密码;
(7). 由shiro完成密码的比对。密码的比对是通过AuthenticatingRealm的credentialsMatcher属性来进行比对的。

要实现特定Realm处理特定身份验证的效果,请参见《shiro实现不同身份使用不同Realm进行验证》

你可能感兴趣的:(shiro)