这是一个很好的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');
org.apache.shiro
shiro-core
1.2.2
org.apache.shiro
shiro-web
1.2.2
org.apache.shiro
shiro-ehcache
1.2.2
org.apache.shiro
shiro-quartz
1.2.2
org.apache.shiro
shiro-spring
1.2.2
commons-collections
commons-collections
3.2.1
/login.jsp = anon
/sysUser/doLogin = anon
/**=user
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetFilterLifecycle
true
shiroFilter
/*
contextConfigLocation
classpath:spring-mybatis.xml,
classpath:spring-shiro-web.xml
org.springframework.web.context.ContextLoaderListener
@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";
}
}
public interface SysUserService {
SysUser getUserByUsername(String username);
Set listRoles(String username);
Set listPermissions(String username);
boolean saveSysUser(SysUser sysUser);
}
@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 listRoles(String username) {
return this.sysUserDao.listRoles(username);
}
@Override
public Set 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();
}
}
}
public interface SysUserDao {
SysUser getUserByUsername(String username);
Set listRoles(String username);
Set listPermissions(String username);
int saveSysUser(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;
}
}
insert into sys_users(username,password,salt,locked)
values(#{username},#{password},#{salt},#{locked})
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();
}
}
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
private Cache 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;
}
}
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;
}
}
当前用户:
有无超级管理员权限:
有
有无普通管理员权限:
有
有哪些权限:
添加用户
查询用户
修改用户
删除用户
退出登录
就显示一句登录失败即可
就显示一句您没有权限即可
登录入口为login.jsp,用户名xl,密码ok,如果登录成功,将跳到main.jsp