这是一个很好的shiro学习网址:http://jinnianshilongnian.iteye.com/blog/2049092
在进行下面的步骤之前,您必须先拥有一个maven管理的ssm项目
第二步:准备数据库这里需要我们准备shiro需要的权限表
这里我给大家提供mysql的建表脚本,直接运行即可
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `sys_permissions`
-- ----------------------------
DROP TABLE IF EXISTS `sys_permissions`;
CREATE TABLE `sys_permissions` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`permission` varchar(100) DEFAULT NULL COMMENT '权限名',
`description` varchar(100) DEFAULT NULL COMMENT '描述',
`available` int(11) DEFAULT NULL COMMENT '是否可用,0表示可用,1表示不可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_permissions
-- ----------------------------
INSERT INTO `sys_permissions` VALUES ('1', 'user:create', '添加用户', '0');
INSERT INTO `sys_permissions` VALUES ('2', 'user:read', '查询用户', '0');
INSERT INTO `sys_permissions` VALUES ('3', 'user:update', '修改用户', '0');
INSERT INTO `sys_permissions` VALUES ('4', 'user:delete', '删除用户', '0');
INSERT INTO `sys_permissions` VALUES ('5', 'book:create', '添加书籍', '0');
INSERT INTO `sys_permissions` VALUES ('6', 'book:read', '查询书籍', '0');
INSERT INTO `sys_permissions` VALUES ('7', 'book:update', '修改书籍', '0');
INSERT INTO `sys_permissions` VALUES ('8', 'book:delete', '删除书籍', '0');
-- ----------------------------
-- Table structure for `sys_roles`
-- ----------------------------
DROP TABLE IF EXISTS `sys_roles`;
CREATE TABLE `sys_roles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`role` varchar(100) DEFAULT NULL COMMENT '角色名',
`description` varchar(100) DEFAULT NULL COMMENT '描述',
`available` int(11) DEFAULT NULL COMMENT '是否可用,0表示可用,1表示不可用',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_roles
-- ----------------------------
INSERT INTO `sys_roles` VALUES ('1', 'super_admin', '*别的角色', '0');
INSERT INTO `sys_roles` VALUES ('2', 'admin', '普通角色', '0');
-- ----------------------------
-- Table structure for `sys_roles_permissions`
-- ----------------------------
DROP TABLE IF EXISTS `sys_roles_permissions`;
CREATE TABLE `sys_roles_permissions` (
`role_id` int(10) unsigned NOT NULL COMMENT '角色id',
`permission_id` int(10) unsigned NOT NULL COMMENT '权限id',
PRIMARY KEY (`role_id`,`permission_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_roles_permissions
-- ----------------------------
INSERT INTO `sys_roles_permissions` VALUES ('1', '1');
INSERT INTO `sys_roles_permissions` VALUES ('1', '2');
INSERT INTO `sys_roles_permissions` VALUES ('1', '3');
INSERT INTO `sys_roles_permissions` VALUES ('1', '4');
INSERT INTO `sys_roles_permissions` VALUES ('1', '5');
INSERT INTO `sys_roles_permissions` VALUES ('1', '6');
INSERT INTO `sys_roles_permissions` VALUES ('1', '7');
INSERT INTO `sys_roles_permissions` VALUES ('1', '8');
-- ----------------------------
-- Table structure for `sys_users`
-- ----------------------------
DROP TABLE IF EXISTS `sys_users`;
CREATE TABLE `sys_users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(100) DEFAULT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '用户名',
`salt` varchar(100) DEFAULT NULL COMMENT '盐',
`locked` int(11) DEFAULT NULL COMMENT '是否锁住,0表示未锁,1表示锁住',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_users
-- ----------------------------
INSERT INTO `sys_users` VALUES ('2', 'xl', '23d49e2b98d2a95d82ecd30c0cb5713f', '9ce31fdc59048b65a282a297335acefc', '0');
-- ----------------------------
-- Table structure for `sys_users_roles`
-- ----------------------------
DROP TABLE IF EXISTS `sys_users_roles`;
CREATE TABLE `sys_users_roles` (
`user_id` int(10) unsigned NOT NULL COMMENT '用户id',
`role_id` int(10) unsigned NOT NULL COMMENT '角色id',
PRIMARY KEY (`user_id`,`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of sys_users_roles
-- ----------------------------
INSERT INTO `sys_users_roles` VALUES ('2', '1');
第三步:pom中导入shiro依赖jar包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
第四步:拷贝spring-shiro-web.xml到resources目录
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 缓存管理器,使用Ehcache实现 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>
<!-- 凭证匹配器,验证密码是否正确,用 下面的类去验证-->
<bean id="credentialsMatcher" class="sdibt.fight.util.RetryLimitHashedCredentialsMatcher">
<constructor-arg ref="cacheManager"/>
<property name="hashAlgorithmName" value="md5"/>
<property name="hashIterations" value="2"/>
<property name="storedCredentialsHexEncoded" value="true"/>
</bean>
<!-- Realm实现 -->
<bean id="userRealm" class="sdibt.fight.util.UserRealm">
<property name="sysUserService" ref="sysUserService"/>
<property name="credentialsMatcher" ref="credentialsMatcher"/>
<!-- 启用缓存 -->
<property name="cachingEnabled" value="true"/>
<!-- 启用身份验证缓存,即缓存AuthenticationInfo信息 -->
<property name="authenticationCachingEnabled" value="false"/>
<!-- 缓存AuthenticationInfo信息的缓存名称 -->
<property name="authenticationCacheName" value="authenticationCache"/>
<!-- 启用授权缓存,即缓存AuthorizationInfo信息 -->
<property name="authorizationCachingEnabled" value="true"/>
<!-- 缓存AuthorizationInfo信息的缓存名称 -->
<property name="authorizationCacheName" value="authorizationCache"/>
</bean>
<!-- 会话ID生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="sid"/>
<property name="httpOnly" value="true"/>
<!-- maxAge=-1表示浏览器关闭时失效此Cookie -->
<property name="maxAge" value="-1"/>
</bean>
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe"/>
<property name="httpOnly" value="true"/>
<!-- 单位为s-->
<property name="maxAge" value="1800"/>
</bean>
<!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!-- rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)-->
<property name="cipherKey"
value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/>
<property name="cookie" ref="rememberMeCookie"/>
</bean>
<bean id="formAuthenticationFilter"
class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
<property name="rememberMeParam" value="rememberMe"/>
</bean>
<!-- 会话DAO -->
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
<property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 会话验证调度器 -->
<bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
<property name="sessionValidationInterval" value="1800000"/>
<property name="sessionManager" ref="sessionManager"/>
</bean>
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<property name="globalSessionTimeout" value="1800000"/>
<property name="deleteInvalidSessions" value="true"/>
<property name="sessionValidationSchedulerEnabled" value="true"/>
<property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
<property name="sessionDAO" ref="sessionDAO"/>
<property name="sessionIdCookieEnabled" value="true"/>
<property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm"/>
<property name="sessionManager" ref="sessionManager"/>
<property name="cacheManager" ref="cacheManager"/>
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean>
<!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
<property name="arguments" ref="securityManager"/>
</bean>
<!-- Shiro的Web过滤器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/login.jsp"/>
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<property name="filterChainDefinitions">
<value>
<!-- 对于过滤器,一般这样使用:
访问一般网页,如个人在主页之类的,我们使用user拦截器即可,user拦截器只要用户登录
(isRemembered()==true or isAuthenticated()==true)过即可访问成功
访问特殊网页,如我的订单,提交订单页面,我们使用authc拦截器即可,authc拦截器会判断用户是否是通过
Subject.login(isAuthenticated()==true)登录的,如果是才放行,否则会跳转到登录页面叫你重新登录 -->
/login.jsp = anon
/sysUser/doLogin = anon
/**=user
</value>
</property>
</bean>
<!-- Shiro生命周期处理器-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
第五步、在web.xml中加入shiro过滤器,并让监听器加载spring-shiro-web.xml,注意下面只是web.xml的部分内容
<!-- 配置shiro过滤器,且该过滤器必须配置在dispatcherServlet之前 ,DelegatingFilterProxy类会自动到Spring容器中
查找名字为shiroFilter的bean并把filter请求交给它处理-->
<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>
<!-- 配置监听器,监听spring上下文中对象的创建.注意:mvc配置文件应最后被加载,因为controller依赖service -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-mybatis.xml,
<!-- 因为shiro配置文件里依赖了service,因此必须先加载spring-mybatis.xml -->
classpath:spring-shiro-web.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
第六步、准备登录界面login.jsp
<form action="${pageContext.request.contextPath }/sysUser/doLogin" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
记住我:<input type="checkbox" value="true" name="rememberMe"><br>
<input type="submit" value="登录">
</form>
第七步、SysUserController类
@Controller
@RequestMapping("/sysUser")
public class SysUserController {
@Resource
private SysUserService sysUserService;
public SysUserService getSysUserService() {
return sysUserService;
}
public void setSysUserService(SysUserService sysUserService) {
this.sysUserService = sysUserService;
}
@RequestMapping("/doLogin")
public String doLogin(SysUser sysUser,String rememberMe) {
System.out.println(rememberMe);
//得到Subject,通过SecurityUtils得到Subject,其会自动绑定到当前线程;如果在web环境在请求结束时需要解除绑定
Subject subject = SecurityUtils.getSubject();
//创建用户名/密码身份验证Token(即用户身份/凭证)
UsernamePasswordToken token=new UsernamePasswordToken(sysUser.getUsername(),sysUser.getPassword());
if(rememberMe!=null) {
//当checkbox勾选之后,rememberMe就不为null,此时启用rememberMe
token.setRememberMe(true);
}else {
//关闭rememberMe
token.setRememberMe(false);
}
try {
/*
* 身份验证,调用subject.login方法进行登录,其会自动委托给SecurityManager.login方法进行登录
* 通过login登录,如果登录失败将抛出相应的AuthenticationException,
* 如果登录成功调用subject.isAuthenticated就会返回true,即已经通过身份验证
* 如果isRemembered返回true,表示是通过记住我功能登录的而不是调用login方法登录的
* isAuthenticated/isRemembered是互斥的,即如果其中一个返回true,另一个返回false
*/
subject.login(token);
} catch (AuthenticationException e) {
/*
* 如果身份验证失败请捕获AuthenticationException或其子类,常见的如:
* DisabledAccountException(禁用的帐号)、
* LockedAccountException(锁定的帐号)、
* UnknownAccountException(错误的帐号)、
* ExcessiveAttemptsException(登录失败次数过多)、
* IncorrectCredentialsException (错误的凭证)、
* ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系
* 对于页面的错误消息展示,最好使用如“用户名/密码错误”而不是“用户名错误”/“密码错误”,防止一些恶意用户非法扫描帐号库
*/
return "login_failed";
}
return "main";
}
@ResponseBody
@RequestMapping("/saveSysUser")
public String saveSysUser(SysUser sysUser) {
try {
//如果b为true,说明添加成功
boolean b = this.sysUserService.saveSysUser(sysUser);
return "添加成功";
} catch (Exception e) {
//如果有异常,说明添加失败
return "添加失败";
}
}
@RequestMapping("/doLogout")
public String doLogout() {
//退出操作后一定要重定向页面
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
}
第八步、SysUserService接口
public interface SysUserService {
SysUser getUserByUsername(String username);
Set<String> listRoles(String username);
Set<String> listPermissions(String username);
boolean saveSysUser(SysUser sysUser);
}
第九步、SysUserServiceImpl实现类
@Service("sysUserService")
public class SysUserServiceImpl implements SysUserService{
@Resource
private SysUserDao sysUserDao;
public SysUserDao getSysUserDao() {
return sysUserDao;
}
public void setSysUserDao(SysUserDao sysUserDao) {
this.sysUserDao = sysUserDao;
}
@Override
public SysUser getUserByUsername(String username) {
return this.sysUserDao.getUserByUsername(username);
}
@Override
public Set<String> listRoles(String username) {
return this.sysUserDao.listRoles(username);
}
@Override
public Set<String> listPermissions(String username) {
return this.sysUserDao.listPermissions(username);
}
/**
* 添加用户
*/
@Override
@Transactional
public boolean saveSysUser(SysUser sysUser) {
//service里主要的工作是,将随机salt和加密后的密码存进数据库
SysUser sysUserToDB = new PasswordHelper().encryptPassword(sysUser);
//保存最终进入数据库的sysUser
int rows = this.sysUserDao.saveSysUser(sysUserToDB);
if(rows==1) {
return true;
}else {
throw new RuntimeException();
}
}
}
第十步、SysUserDao接口
public interface SysUserDao {
SysUser getUserByUsername(String username);
Set<String> listRoles(String username);
Set<String> listPermissions(String username);
int saveSysUser(SysUser sysUser);
}
第十一步、SysUser实体类
public class SysUser implements Serializable {
private int id;
private String username;
private String password;
private String salt;
private int locked;
public String getCredentialsSalt() {
return username + salt;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public int getLocked() {
return locked;
}
public void setLocked(int locked) {
this.locked = locked;
}
}
第十二步、SysUser.xml映射文件
<?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="sdibt.fight.dao.SysUserDao">
<!-- 根据用户名查找用户 -->
<select id="getUserByUsername" parameterType="java.lang.String" resultType="sdibt.fight.entity.SysUser">
select * from sys_users where username=#{username} and locked=0
</select>
<!-- 查询用户所有角色 -->
<select id="listRoles" parameterType="java.lang.String" resultType="java.lang.String">
select r.role from sys_users u inner join sys_users_roles ur on u.id=ur.user_id
inner join sys_roles r on ur.role_id=r.id where u.username=#{username} and u.locked=0
and r.available=0
</select>
<!-- 查询用户所有权限,返回值是权限名集合 -->
<select id="listPermissions" parameterType="java.lang.String" resultType="java.lang.String">
select p.permission from sys_users u inner join sys_users_roles ur on u.id=ur.user_id
inner join sys_roles r on ur.role_id=r.id inner join sys_roles_permissions rp
on r.id=rp.role_id inner join sys_permissions p on p.id=rp.permission_id
where u.username=#{username} and u.locked=0 and r.available=0 and p.available=0
</select>
<!-- 添加用户 -->
<insert id="saveSysUser" parameterType="sdibt.fight.entity.SysUser">
insert into sys_users(username,password,salt,locked)
values(#{username},#{password},#{salt},#{locked})
</insert>
</mapper>
第十三步、UserRealm类,用于获取安全数据源,建议放到util包下
public class UserRealm extends AuthorizingRealm {
private SysUserService sysUserService;
public SysUserService getSysUserService() {
return sysUserService;
}
public void setSysUserService(SysUserService sysUserService) {
this.sysUserService = sysUserService;
}
/**
* 获取权限信息,只有在身份验证成功后才调用此方法获取权限信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//获取用户名
String username = (String)principals.getPrimaryPrincipal();
//new一个授权信息
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//给授权信息设置角色集合,只能放角色名
authorizationInfo.setRoles(sysUserService.listRoles(username));
//给授权信息设置权限集合
authorizationInfo.setStringPermissions(sysUserService.listPermissions(username));
//返回用户授权信息
return authorizationInfo;
}
/**
* 获取身份验证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户名
String username = (String)token.getPrincipal();
//根据用户名获取User对象
SysUser user = sysUserService.getUserByUsername(username);
if(user == null) {
//找不到账号
throw new UnknownAccountException();
}
if(user.getLocked()==1) {
//帐号锁定
throw new LockedAccountException();
}
/*
* new一个身份验证信息
*/
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
//用户名
user.getUsername(),
//从数据库中查出的密文密码
user.getPassword(),
//credentialsSalt=username+salt
ByteSource.Util.bytes(user.getCredentialsSalt()),
//realm名称
getName()
);
Session session = getSession();
//将当前用户放进session
session.setAttribute("username", username);
/*
* 返回身份验证信息,将交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
* CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配
*/
return authenticationInfo;
}
/**
* 获取shiro封装的session
*/
private Session getSession(){
try{
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession(false);
if (session == null){
session = subject.getSession();
}
if (session != null){
return session;
}
}catch (InvalidSessionException e){
}
return null;
}
//以下是一些清空realm缓存的方法
@Override
public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
}
@Override
public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
super.clearCachedAuthenticationInfo(principals);
}
@Override
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
}
public void clearAllCachedAuthorizationInfo() {
getAuthorizationCache().clear();
}
public void clearAllCachedAuthenticationInfo() {
getAuthenticationCache().clear();
}
public void clearAllCache() {
clearAllCachedAuthenticationInfo();
clearAllCachedAuthorizationInfo();
}
}
第十四步、RetryLimitHashedCredentialsMatcher类,用于验证密码是否正确,建议放到util包下
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
private Cache<String, AtomicInteger> passwordRetryCache;
public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {
passwordRetryCache = cacheManager.getCache("passwordRetryCache");
}
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
//获取用户名
String username = (String)token.getPrincipal();
//从缓存中获取该用户已经输入密码的尝试次数
AtomicInteger retryCount = passwordRetryCache.get(username);
if(retryCount == null) {
retryCount = new AtomicInteger(0);
//将用户输入密码的尝试次数缓存起来
passwordRetryCache.put(username, retryCount);
}
if(retryCount.incrementAndGet() > 5) {
//密码输入次数超过五次
throw new ExcessiveAttemptsException();
}
/*
* token是表单上输入的用户名和密码,info是从数据中查的信息,将作密码比对
*/
boolean matches = super.doCredentialsMatch(token, info);
if(matches) {
//清楚尝试次数
passwordRetryCache.remove(username);
}
return matches;
}
}
第十五步、PasswordHelper类,密码帮助类,建议放到util包下
public class PasswordHelper {
private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
private String algorithmName = "md5";
private int hashIterations = 2;
public void setRandomNumberGenerator(RandomNumberGenerator randomNumberGenerator) {
this.randomNumberGenerator = randomNumberGenerator;
}
public void setAlgorithmName(String algorithmName) {
this.algorithmName = algorithmName;
}
public void setHashIterations(int hashIterations) {
this.hashIterations = hashIterations;
}
/**
* 加密密码
*/
public SysUser encryptPassword(SysUser sysUser) {
//设置随机salt
sysUser.setSalt(randomNumberGenerator.nextBytes().toHex());
//密码明文+随机salt=密码密文
String newPassword = new SimpleHash(
algorithmName,
sysUser.getPassword(),
//credentialsSalt=username+salt
ByteSource.Util.bytes(sysUser.getCredentialsSalt()),
hashIterations).toHex();
//设置密码密文
sysUser.setPassword(newPassword);
return sysUser;
}
}
第十六步、准备其他jsp页面
一、main.jsp
<!-- 相当于Subject.getPrincipals().oneByType(String.class) -->
当前用户:<shiro:principal type="java.lang.String"/><br>
有无超级管理员权限:
<shiro:hasRole name="super_admin">
有
</shiro:hasRole>
<br>
有无普通管理员权限:
<shiro:hasRole name="admin">
有
</shiro:hasRole>
<br>
有哪些权限:
<shiro:hasPermission name="user:create">
<a href="${pageContext.request.contextPath }/sysuser_add.jsp">添加用户</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:read">
<a href="#">查询用户</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:update">
<a href="#">修改用户</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:delete">
<a href="#">删除用户</a>
</shiro:hasPermission>
<br>
<a href="${pageContext.request.contextPath }/sysUser/doLogout">退出登录</a>
二、sysuser_add.jsp
<form action="${pageContext.request.contextPath }/sysUser/saveSysUser" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
是否锁住用户:<input type="text" name="locked">
<input type="submit" value="添加用户">
</form>
三、login_failed.jsp
就显示一句登录失败即可
四、unauthorized.jsp
就显示一句您没有权限即可
第十七步、运行测试
登录入口为login.jsp,用户名xl,密码ok,如果登录成功,将跳到main.jsp