第一步:导入需要的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中默认的过滤器:
整个认证流程:
(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进行验证》