源码地址 https://github.com/ostars/springboot-fast.git 分支:dev_shiro
项目结构
├── doc // doc files.
├── log // log files.
├── src/main
│ ├──java/org/ostars/springbootfast // Specific code.
│ ├──security // shiro config
│ ├──├──GlobalExceptionHandler // 未授权进入403页面
│ ├──├──ShiroConfig // 注册和配置不需要shiro控制的资源和页面
│ ├──├──ShiroRealm // 验证和授权
│ ├──├──ShiroTagConfig // shiro标签
│ ├──resources
│ ├──ehcache
│ ├──├──ehcache.xml // 使用ehcache做二级缓存
├── src/test // test.
├── .gitignore
├── LICENSE
├── README.md
ShiroConfig.java
package org.ostars.springbootfast.security;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* shiro config
*
* @author isaac
* @date 2019/10/9
*/
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
@Bean
public ShiroRealm shiroRealm() {
ShiroRealm shiroRealm = new ShiroRealm();
shiroRealm.setCacheManager(cacheManager());
return shiroRealm;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
securityManager.setCacheManager(cacheManager());
securityManager.setRememberMeManager(cookieRememberMeManager());
return securityManager;
}
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
public EhCacheManager cacheManager() {
CacheManager cacheManager = CacheManager.getCacheManager("es");
if (cacheManager == null) {
try {
cacheManager = CacheManager.create(ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache.xml"));
} catch (IOException e) {
throw new RuntimeException("initialize cacheManager failed");
}
}
EhCacheManager ehCacheManager = new EhCacheManager();
ehCacheManager.setCacheManager(cacheManager);
return ehCacheManager;
}
@Bean
public SimpleCookie simpleCookie() {
SimpleCookie simpleCookie = new SimpleCookie();
simpleCookie.setHttpOnly(true);
simpleCookie.setMaxAge(604800);
simpleCookie.setName("standardManagement");
return simpleCookie;
}
@Bean
public CookieRememberMeManager cookieRememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));
cookieRememberMeManager.setCookie(simpleCookie());
return cookieRememberMeManager;
}
}
ShiroRealm.java
package org.ostars.springbootfast.security;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.ostars.springbootfast.enums.StatusEnum;
import org.ostars.springbootfast.model.base.SysUserModel;
import org.ostars.springbootfast.service.base.SysResourceService;
import org.ostars.springbootfast.service.base.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import java.util.List;
import static org.ostars.springbootfast.utils.GlobalConstant.ADMINORGID;
import static org.ostars.springbootfast.utils.GlobalConstant.ISADMIN;
/**
* shiro realm
*
* @author isaac
* @date 2019/10/9
*/
public class ShiroRealm extends AuthorizingRealm {
@Autowired
private SysUserService sysUserService;
@Autowired
private SysResourceService sysResourceService;
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String loginName = authenticationToken.getPrincipal().toString();
if (StringUtils.isEmpty(loginName)) {
throw new AccountException("empty loginName");
}
List<SysUserModel> userModels = this.sysUserService.selectByModel(new SysUserModel(loginName));
if (userModels.size() == 0) {
throw new LockedAccountException("no account find");
}
if (userModels.size() > 1) {
throw new LockedAccountException("duplicate account");
}
SysUserModel sysUserModel = userModels.get(0);
if (StatusEnum.DISABLE.getValue().equals(sysUserModel.getStatus())) {
throw new LockedAccountException("account locked");
}
if (ISADMIN.equals(sysUserModel.getAdminFlag())) {
sysUserModel.setOrgId(ADMINORGID);
}
return new SimpleAuthenticationInfo(sysUserModel, sysUserModel.getPassword(), getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
SysUserModel sysUserModel = (SysUserModel) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
if (ISADMIN.equals(sysUserModel)) {
info.addStringPermission("*:*");
return info;
}
List<String> permissionList = this.sysResourceService.selectResourceByUserId(sysUserModel.getId());
info.addStringPermissions(permissionList);
return info;
}
}
ShiroConTagConfig.java
package org.ostars.springbootfast.security;
import com.jagregory.shiro.freemarker.ShiroTags;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import freemarker.template.Configuration;
import org.springframework.context.annotation.ComponentScan;
/**
* shiro tag config
*
* @author isaac
* @date 2019/10/9
*/
@ComponentScan
public class ShiroTagConfig implements InitializingBean {
@Autowired
private Configuration configuration;
@Override
public void afterPropertiesSet() {
configuration.setSharedVariable("shiro", new ShiroTags());
}
}
GlobalExceptionHandler.java
package org.ostars.springbootfast.security;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletRequest;
/**
* global exception handler
*
* @author isaac
* @date 2019/10/9
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = UnauthorizedException.class)
public String defaultUnauthorizedExceptionHandler(HttpServletRequest request, Exception e) {
return "403";
}
}
LoginUtil.java
package org.ostars.springbootfast.utils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.ostars.springbootfast.model.base.SysUserModel;
/**
* login util
*
* @author isaac
* @date 2019/10/10
*/
public class LoginUtil {
public static SysUserModel getLoginUser() {
Subject subject = SecurityUtils.getSubject();
return (SysUserModel) subject.getPrincipals().getPrimaryPrincipal();
}
}
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
</ehcache>
LoginController.java
package org.ostars.springbootfast.controller.base;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.ostars.springbootfast.utils.LoginUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* login controller
*
* @author isaac
* @date 2019/10/9
*/
@RestController
public class LoginController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@PostMapping("login")
public Map<String, Object> login(String userName, String password, boolean remeberMe, HttpServletRequest request) {
Map<String, Object> map = new HashMap<>();
map.put("success", false);
Subject currentUser = SecurityUtils.getSubject();
password = new Md5Hash(password).toHex();
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
token.setRememberMe(remeberMe);
try {
currentUser.login(token);
} catch (UnknownAccountException uae) {
logger.info(uae.getMessage());
map.put("info", "您输入的用户名或密码错误!");
return map;
} catch (IncorrectCredentialsException ice) {
logger.info(ice.getMessage());
map.put("info", "您输入的用户名或密码错误!");
return map;
} catch (LockedAccountException lae) {
logger.info(lae.getMessage());
map.put("info", "此用户已经被锁定不能登录,请与管理员联系!");
return map;
} catch (DisabledAccountException lae) {
logger.info(lae.getMessage());
map.put("info", "此用户已经被禁用不能登录,请与管理员联系!");
return map;
} catch (ExcessiveAttemptsException eae) {
logger.info(eae.getMessage());
map.put("info", "您输入的错误次数过多!");
return map;
} catch (AuthenticationException ae) {
logger.info(ae.getMessage());
map.put("info", "您输入的用户名或密码错误!");
return map;
}
map.put("success", currentUser.isAuthenticated());
request.getSession().setAttribute("isAdmin", LoginUtil.getLoginUser().getAdminFlag());
return map;
}
}