shiro所需要的包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-cas</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.4.0</version>
</dependency>
public class AuthRealm extends AuthorizingRealm {
@Autowired
private ISysAdminService adminService;
@Autowired
private ISysAdminRoleService adminRoleService;
@Autowired
private ISysRolePermService rolePermService;
//认证.登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("-----------------认证.登录-------------------");
UsernamePasswordToken utoken = (UsernamePasswordToken) token;//获取用户输入的token
String username = utoken.getUsername();
//处理session
SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager();
DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager();
//获取当前已登录的用户session列表
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
for (Session session : sessions) {
//清除该用户以前登录时保存的session
// IotdUserEntity en=(IotdUserEntity)(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
// String phone=en.getPhone();
//如果和当前session是同一个session,则不剔除
if (SecurityUtils.getSubject().getSession().getId().equals(session.getId()))
break;
SysAdmin admin = (SysAdmin) (session.getAttribute("sysAdmin"));
if (admin != null) {
String adminName = admin.getLoginName();
if (username.equals(adminName)) {
System.out.println(username + "已登录,剔除中...........");
sessionManager.getSessionDAO().delete(session);
}
}
}
//获取用户信息
SysAdmin sysAdmin = adminService.getByLoginName(username);
if(sysAdmin == null) {
throw new UnknownAccountException();
}
if(sysAdmin.getIsLock() == 1) {//被锁定
throw new LockedAccountException();
}
if(sysAdmin.getIsEnable() == 1) {//该账号未被启用
throw new DisabledAccountException();
}
//放入shiro.调用CredentialsMatcher检验密码
SimpleAuthenticationInfo rst = new SimpleAuthenticationInfo(sysAdmin, sysAdmin.getPassword(), this.getClass().getName());
return rst;
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
SysAdmin admin = (SysAdmin) principal.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
//获取该用户的所有角色
List<Integer> listId = adminRoleService.getRoleIdByAdminId(admin.getSysAdminId());
//查询该用户的权限
List<String> list = rolePermService.getAuthCodeListByRoles(listId);
info.addStringPermissions(list);
return info;
}
}
/**
* shiro配置类
* @author Administrator
*
*/
@Configuration
public class ShiroConfiguration {
/**
* 创建ShiroFilterFactoryBean
*/
@Bean(name="shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
/**
* shiro常用拦截器
* anon: 无需认证就可访问
* authc: 需要认证才能访问
* user :使用rememberMe的功能可直接访问
* perms: 必须有资源的权限才可以访问
* role : 该资源必须得到角色的权限才可以访问
*/
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
//配置核心安全事务管理器
@Bean(name="securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
System.err.println("--------------shiro已经加载----------------");
DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
manager.setRealm(authRealm);
manager.setSessionManager(sessionManager());
// <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
manager.setCacheManager(ehCacheManager());
//注入记住我管理器;
manager.setRememberMeManager(rememberMeManager());
return manager;
}
@Bean(name = "sessionManager")
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
return sessionManager;
}
//配置自定义的权限登录器
@Bean(name="authRealm")
public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
AuthRealm authRealm=new AuthRealm();
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
//配置自定义的密码比较器
@Bean(name="credentialsMatcher")
public CredentialsMatcher credentialsMatcher() {
return new CredentialsMatcher(ehCacheManager());
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) {
AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}
//-----------------------------------------------
/**
* LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
* 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
* 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
*
* @return
*/
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
/**
* ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm, 负责用户的认证和权限的处理
*
* @return
*/
@Bean(name = "myShiroRealm")
@DependsOn("lifecycleBeanPostProcessor")
public AuthRealm myShiroRealm() {
AuthRealm myShiroRealm = new AuthRealm();
return myShiroRealm;
}
/**
* EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
* 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
*
* @return
*/
@Bean(name = "ehCacheManager")
@DependsOn("lifecycleBeanPostProcessor")
public EhCacheManager ehCacheManager() {
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return cacheManager;
}
/**
* 自定义shiroSession的cookie,如果不设置默认JSESSIONID,
* 会与tomcat等默认cookie名重复,sessionIdCookie用于保存sessionId标识
*
* @return
*/
@Bean(name = "rememberMeCookie")
public SimpleCookie rememberMeCookie() {
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:
// 设为true后,只能通过http访问,javascript无法访问
// 防止xss读取cookie
simpleCookie.setHttpOnly(true);
// <!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* cookie管理对象;
* 记住我的配置
* @return
*/
@Bean(name = "rememberMeManager")
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
/**
* DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
*
* @return
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}
/**
* thymeleaf模板使用shiro注解
* @return
*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
}
/**
* 自定义密码比较
* @author Administrator
*
*
*/
public class CredentialsMatcher extends SimpleCredentialsMatcher {
@Autowired
private ISysAdminService adminService;
private Cache<String, AtomicInteger> passwordRetryCache;
public CredentialsMatcher(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) {
// 如果用户没有登陆过,登陆次数加1 并放入缓存
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
}
if (retryCount.incrementAndGet() > 3) {
// 如果用户登陆失败次数大于3次 抛出锁定用户异常 并修改数据库字段
SysAdmin admin = adminService.getByLoginName(username);
if (admin != null && admin.getIsLock() == 0){
// 数据库字段 默认为 0 就是未锁定状态 所以 要改为1
// 修改数据库的状态字段为锁定
admin.setIsLock((byte) 1);
adminService.updateById(admin);
}
// 抛出用户锁定异常
throw new LockedAccountException();
}
// 判断用户账号和密码是否正确
boolean matches = super.doCredentialsMatch(token, info);
if (matches) {
// 如果正确,从缓存中将用户登录计数 清除
passwordRetryCache.remove(username);
}
return matches;
}
/**
* 根据用户名 解锁用户
* @param username
* @return
*/
public void unlockAccount(String username){
passwordRetryCache.remove(username);
}
}
/**
* 生成验证码
*/
@RequestMapping(value = "/getVerify")
public void getVerify(HttpServletRequest request, HttpServletResponse response) {
try {
response.setContentType("image/jpeg");// 设置相应类型,告诉浏览器输出的内容为图片
response.setHeader("Pragma", "No-cache");// 设置响应头信息,告诉浏览器不要缓存此内容
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expire", 0);
RandomValidateCodeUtil randomValidateCode = new RandomValidateCodeUtil();
randomValidateCode.getRandcode(request, response);// 输出验证码图片方法
} catch (Exception e) {
result(HTTP_VALID,"获取验证码失败",ICON_ERROR);
}
}
/**
* 登录校验
* @param admin
* @return
* @throws Exception
*/
@RequestMapping(value="/checkLogin" ,method=RequestMethod.POST)
@ResponseBody
// @OperLog(operModul="登录",operType="checkLogin",operDesc="验证用户名密码")
public AjaxResult checkLogin(HttpSession session ,SysAdmin admin,String captcha){
try {
// String random = (String) session.getAttribute("RANDOMVALIDATECODEKEY");
// if(captcha.equals("") || !random.equals(captcha)) {
// return result(HTTP_VALID,"验证码错误",ICON_EXIST);
// }
/**
* shiro 认证操作
*/
//1.获取Subject对象
Subject subject = SecurityUtils.getSubject();
//2.封装用户数量
UsernamePasswordToken token = new UsernamePasswordToken(admin.getLoginName(), DesAesUtil.encryptDES(admin.getPassword()));
//3.执行登录方法
subject.login(token);
SysAdmin loginAdmin = (SysAdmin)SecurityUtils.getSubject().getPrincipal();
session.setAttribute("sysAdmin", loginAdmin);
JSONObject json = new JSONObject();
json.put("url", "/Bmc/sys-menu/menu");
return result(HTTP_SUCCESS , MSG_SUCCESS , ICON_SUCCESS , json);
}catch (UnknownAccountException e) {
return result(HTTP_VALID , "用户名不存在" , ICON_EXIST);
}catch(IncorrectCredentialsException e) {
return result(HTTP_VALID , "密码不正确" , ICON_EXIST);
}catch(NullPointerException e) {
return result(HTTP_VALID , "验证码过期" , ICON_EXIST);
}catch(LockedAccountException e) {
return result(HTTP_VALID , "该账号由于登录次数过多已被锁定" , ICON_EXIST);
}catch(DisabledAccountException e) {
return result(HTTP_VALID , "该账号未被启用" , ICON_EXIST);
}catch(Exception e) {
return result(HTTP_VALID , "该账号存在异常" , ICON_EXIST);
}
}
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<defaultCache
eternal="false"
maxElementsInMemory="1000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="0"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LRU" />
<!-- 登录失败次数缓存
注意 timeToLiveSeconds 设置为300秒 也就是5分钟
可以根据自己的需求更改
-->
<cache name="passwordRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="0"
timeToLiveSeconds="300"
overflowToDisk="false"
statistics="true">
</cache>
</ehcache>