目录
2.3 RetryLimitHashedCredentialsMatcher
扫描二维码关注公众号,回复:
9559615 查看本文章
结构图:
1、新增用户并加密
1.1 Table DDL
CREATE TABLE `user` (
`id` varchar(30) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`sex` varchar(30) DEFAULT NULL,
`username` varchar(32) DEFAULT NULL,
`password` varchar(32) DEFAULT NULL,
`role` varchar(32) DEFAULT NULL,
`permissions` varchar(100) DEFAULT NULL,
`Locked` varchar(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.2 Control
@RequestMapping(value = "/shiro/region", method = RequestMethod.POST)
@ResponseBody
public String shiroRegion(String username, String password) {
User user = new User();
user.setId("005");
user.setName("lucy");
user.setSex("women");
user.setUsername("005");
user.setPassword("123");
user.setRole("admin");
user.setPermissions("delete");
user.setLocked("0");
shiroUserService.AddUser(user);
return "";
}
1.3 Service
@Override
public void AddUser(User user) {
RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
String algorithmName = "md5";
int hashIterations = 2;
//用用户名作为salt
String salt = user.getUsername();
SimpleHash hash = new SimpleHash(algorithmName, user.getPassword(), salt, hashIterations);
user.setPassword(hash.toHex());
userMapper.insert(user);
}
2、用户登录并验证
2.1 controller
@RequestMapping(value = "/shiro/login", method = RequestMethod.POST)
@ResponseBody
public String shiroLogin(String username, String password) {
String error = null;
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
} catch (IncorrectCredentialsException ice) {
// 捕获密码错误异常
return "密码错误";
} catch (UnknownAccountException uae) {
// 捕获未知用户名异常
return "用户名不存在";
} catch (ExcessiveAttemptsException eae) {
// 捕获错误登录过多的异常
return "登录次数超过5次!";
}
User user = shiroUserService.findByUsername(username);
/**
* 登录完成以后,当前用户信息被保存进Session。 这个Session是通过Shiro管理的会话对象,要获取依然必须通过Shiro。
* 传统的Session中不存在User对象
*/
subject.getSession().setAttribute("user", user);
return "sucess";
}
2.2 UserRealm
package com.comqing.common.utils;
public class UserRealm extends AuthorizingRealm {
// 用户对应的角色信息与权限信息都保存在数据库中,通过UserService获取数据
@Autowired
private ShiroUserService userService;
/**
* 提供用户信息返回权限信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 根据用户名查询当前用户拥有的角色
String roles = userService.findRoles(username);
Set<String> roleNames = new HashSet<String>();
roleNames.add(roles);
// 将角色名称提供给info
authorizationInfo.setRoles(roleNames);
// 根据用户名查询当前用户权限
String permissions = userService.findPermissions(username);
Set<String> permissionNames = new HashSet<String>();
permissionNames.add(permissions);
// 将权限名称提供给info
authorizationInfo.setStringPermissions(permissionNames);
return authorizationInfo;
}
/**
* 提供账户信息返回认证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.findByUsername(username);
if (user == null) {
// 用户名不存在抛出异常
throw new UnknownAccountException();
}
if (user.getLocked() == "0") {
// 用户被管理员锁定抛出异常
throw new LockedAccountException();
}
// 当前 Realm 的 name
String realmName = this.getName();
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(),
user.getPassword(), ByteSource.Util.bytes(user.getUsername()), realmName);
return authenticationInfo;
}
}
2.3 RetryLimitHashedCredentialsMatcher
package com.comqing.common.utils;
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
// 声明一个缓存接口,这个接口是Shiro缓存管理的一部分,它的具体实现可以通过外部容器注入
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);
}
// 自定义一个验证过程:当用户连续输入密码错误5次以上禁止用户登录一段时间
if (retryCount.incrementAndGet() > 5) {
throw new ExcessiveAttemptsException();
}
boolean match = super.doCredentialsMatch(token, info);
if (match) {
passwordRetryCache.remove(username);
}
return match;
}
}
3、用户登出
参考:http://blog.csdn.net/clj198606061111/article/details/24185023
@RequestMapping(value = "/shiro/logout", method = RequestMethod.POST)
@ResponseBody
public String shiroLogout() {
Subject subject = SecurityUtils.getSubject();
if (subject.isAuthenticated()) {
subject.logout(); // session 会销毁,在SessionListener监听session销毁,清理权限缓存
}
return "sucess";
}