application-dev.yml
server:
port: 8080
servlet:
context-path: /
ip:
mysql: localhost:3306
localhost: localhost
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://${ip.mysql}/kuma?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
redis:
host: ${ip.localhost}
port: 6379
jedis:
pool:
max-idle: 8
min-idle: 0
max-active: 8
max-wait: -1
timeout: 0
# jpa:
# hibernate:
# ddl-auto: none
# show-sql: true
thymeleaf:
cache: false
devtools:
restart:
enabled: false
# additional-paths: resources/**,static/**,templates/**,src/main/java
resources:
static-locations: classpath:/static/, classpath:/templates/
# cache:
# ehcache:
# config: classpath:ehcache.xml
#
cache:
type: simple
# 每次应用启动不检查Activiti数据表是否存在及版本号是否匹配,提升应用启动速度
# activiti:
# database-schema-update: false
# history-level: full
# font:
# activityFontName: 宋体
# labelFontName: 宋体
# check-process-definitions: true
mybatis:
mapper-locations: classpath:mapping/**/*.xml
type-aliases-package: com.kuma.platform.model
#zookeeper:
# address: 127.0.0.1:2181
# timeout: 4000
#showSql
logging:
level:
com:
kuma:
platform:
dao: debug
upload:
server:
domain: http://${ip.localhost}:${server.port}${server.servlet.context-path}
image:
dir: D:/upload/images
format: swf,wmv,gif,png,jpg,jpeg,bmp
size: 151200000
file:
dir: D:/upload/file
video:
dir: D:/upload/video
SpringShiroConfig.java
package com.kuma.platform.config;
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.kuma.platform.shiro.CustomRealm;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.LinkedHashMap;
import java.util.Map;
@Configuration
public class SpringShiroConfig {
@Value("${spring.redis.host}")
String host;
@Value("${spring.redis.port}")
int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Autowired
private CustomRealm realm;
public SpringShiroConfig() {
System.out.println("SpringShiroConfig init ......");
}
@Bean(name = "lifecycleBeanPostProcessor")
public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
// creator.setUsePrefix(true);
return creator;
}
@Bean
public MethodInvokingFactoryBean getMethodInvokingFactoryBean(@Qualifier("securityManager")SecurityManager securityManager) {
MethodInvokingFactoryBean methodInvokingFactoryBean=new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
methodInvokingFactoryBean.setArguments(securityManager);
return methodInvokingFactoryBean;
}
//get
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager")SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
//get
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setLoginUrl("/logon");
shiroFilterFactoryBean.setUnauthorizedUrl("/logon");
shiroFilterFactoryBean.setSuccessUrl("/index");
// shiroFilterFactoryBean.setLoginUrl("/user/login.html");
// shiroFilterFactoryBean.setUnauthorizedUrl("/user/login.html");
shiroFilterFactoryBean.setSecurityManager(securityManager);
loadShiroFilterChain(shiroFilterFactoryBean);
return shiroFilterFactoryBean;
}
//get
private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean) {
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
filterChainDefinitionMap.put("/layuiadmin/**", "anon");
filterChainDefinitionMap.put("/login.html", "anon");
filterChainDefinitionMap.put("/**/login/**", "anon");
filterChainDefinitionMap.put("/api/**", "anon");
filterChainDefinitionMap.put("/logon", "anon");
filterChainDefinitionMap.put("/logout", "anon");
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/index", "user");
filterChainDefinitionMap.put("/index.html", "user");
filterChainDefinitionMap.put("/**", "authc");
/*
* filterChainDefinitionMap.put("/mydemo/login", "anon");
* filterChainDefinitionMap.put("/user/info**", "authc");
* filterChainDefinitionMap.put("/admin/listUser**","authc,perms[admin:manage]");
*/
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
}
//get
@Bean(name = "sessionManager")
public DefaultWebSessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setCacheManager(cacheManager());
sessionManager.setGlobalSessionTimeout(1000*60);//单位:毫秒
// sessionManager.setDeleteInvalidSessions(true);
sessionManager.setSessionIdCookieEnabled(true);
sessionManager.setSessionDAO(redisSessionDAO());
return sessionManager;
}
//get
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager(@Qualifier("sessionManager") DefaultWebSessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
securityManager.setSessionManager(sessionManager);
securityManager.setCacheManager(cacheManager());
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
public SimpleCookie rememberMeCookie() {
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// 记住我cookie生效时间30天 ,单位秒。 注释掉,默认永久不过期 2018-07-15
simpleCookie.setMaxAge(60*60);
return simpleCookie;
}
/**
* cookie管理对象;记住我功能
*
* @return
*/
public CookieRememberMeManager rememberMeManager() {
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
// cookieRememberMeManager.setCipherKey(Base64.decode("1QWLxg+NYmxraMoxAXu/Iw=="));
return cookieRememberMeManager;
}
//为了在thymeleaf里使用shiro的标签的bean
@Bean
public ShiroDialect shiroDialect() {
return new ShiroDialect();
}
/**
* cacheManager 缓存 redis实现
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
return redisCacheManager;
}
/**
* 配置shiro redisManager
* 使用的是shiro-redis开源插件
*
* @return
*/
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost(host);
redisManager.setPort(port);
redisManager.setExpire(1800);// 配置缓存过期时间
redisManager.setTimeout(timeout);
return redisManager;
}
/**
* RedisSessionDAO shiro sessionDao层的实现 通过redis
* 使用的是shiro-redis开源插件
*/
@Bean
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(redisManager());
return redisSessionDAO;
}
}
CustomRealm.java
package com.kuma.platform.shiro;
import com.kuma.platform.model.po.admin.AdminMenuPo;
import com.kuma.platform.model.po.admin.AdminUserPo;
import com.kuma.platform.service.admin.AdminMenuService;
import com.kuma.platform.service.admin.AdminUserService;
import com.kuma.platform.utils.RedisApiUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* 自定义Realm
* @author super_dev_001
* @date 2020/4/6
* @param
* @return
*/
@Component
public class CustomRealm extends AuthorizingRealm {
@Autowired
private AdminUserService adminUserService;
@Autowired
private AdminMenuService adminMenuService;
private static Logger logger= LoggerFactory.getLogger(CustomRealm.class);
public CustomRealm() {
logger.info("CustomRealm====================");
}
@Override
public String getName() {
return "CustomRealm";
}
@Bean(name = "credentialsMatcher")
public HashedCredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5");
credentialsMatcher.setHashIterations(1024);
return credentialsMatcher;
}
@Override
public void setCredentialsMatcher(@Qualifier("credentialsMatcher")CredentialsMatcher credentialsMatcher){
super.setCredentialsMatcher(credentialsMatcher);
}
/**
* realm授权方法 从输入参数principalCollection得到身份信息 根据身份信息到数据库查找权限信息 将权限信息添加给授权信息对象
* 返回 授权信息对象(判断用户访问url是否在权限信息中没有体现)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
AdminUserPo user = null;
// AdminUserPo user = (AdminUserPo) principalCollection.getPrimaryPrincipal();
Long userId = (Long)principalCollection.getPrimaryPrincipal();
List<String> btnList = null;
try{
user = this.adminUserService.queryById(userId);
String roleIds = user.getRoleIds();
btnList = adminMenuService.queryBtnsByRoles(roleIds);
}catch (Exception e){
e.printStackTrace();
}
// 用户权限列表
Set<String> permsSet = new HashSet<String>();
if(btnList!=null && btnList.size()>0){
permsSet.addAll(btnList);
}
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setStringPermissions(permsSet);
return info;
}
/**
* 表单认证过滤器认证时会调用自定义Realm的认证方法进行认证,成功回到index.do,再跳转到index.jsp页面
*
* 前提:表单认证过滤器收集和组织用户名和密码信息封装为token对象传递给此方法
*
* token:封装了身份信息和凭证信息 2步骤:比对身份 信息;比对凭证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
String password = new String((char[]) token.getCredentials());
// 查询用户信息
AdminUserPo adminUserPo = null;
try{
adminUserPo = adminUserService.queryByUserName(username);
}catch (Exception e){
e.printStackTrace();
}
// 账号不存在
if (adminUserPo == null ) {
throw new UnknownAccountException("账号不存在!");
}
// 密码错误
if (!password.equals(adminUserPo.getPassword())) {
throw new IncorrectCredentialsException("账号或密码不正确!");
}
// 账号未分配角色
if (adminUserPo.getRoleIds() == null ) {
throw new UnknownAccountException("账号未分配角色!");
}
//super_dev_001 2020/2/8 登录成功,查询菜单
try{
List<AdminMenuPo> menuList = this.adminMenuService.queryByRoles(adminUserPo.getRoleIds());
adminUserPo.setMenuList(menuList);
RedisApiUtils.save(""+adminUserPo.getId(),adminUserPo);
// EhcacheUtils.putUser(adminUserPo);
}catch (Exception e){
e.printStackTrace();
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(adminUserPo.getId(), password, ByteSource.Util.bytes(username), getName());
return info;
}
}
ShiroUtils.java
package com.kuma.platform.shiro;
import com.alibaba.fastjson.JSON;
import com.kuma.platform.model.po.admin.AdminUserPo;
import com.kuma.platform.utils.RedisApiUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
/**
* super_dev_001 2020/2/3
*/
public class ShiroUtils {
public static Session getSession() {
return SecurityUtils.getSubject().getSession(true);
}
public static Subject getSubject() {
return SecurityUtils.getSubject();
}
public static AdminUserPo getUserEntity() {
Long userId = (Long)getSubject().getPrincipal();
Object userObj = RedisApiUtils.get(""+userId);
if(userObj!=null){
AdminUserPo rec = JSON.parseObject(JSON.toJSONString(userObj),AdminUserPo.class);
return rec;
}
return null;
}
public static Long getUserId() {
return getUserEntity()==null?null:getUserEntity().getId();
}
public static String getUserName() {
return getUserEntity()==null?null:getUserEntity().getUserName();
}
public static void setSessionAttribute(Object key, Object value) {
getSession().setAttribute(key, value);
}
public static Object getSessionAttribute(Object key) {
return getSession().getAttribute(key);
}
public static boolean isLogin() {
return SecurityUtils.getSubject().getPrincipal() != null;
}
public static void logout() {
RedisApiUtils.del(""+getUserId());
SecurityUtils.getSubject().logout();
// EhcacheUtils.removeUser();
}
public static String getKaptcha(String key) {
String kaptcha = getSessionAttribute(key).toString();
getSession().removeAttribute(key);
return kaptcha;
}
}
RedisApiUtils.java
package com.kuma.platform.utils;
import com.alibaba.fastjson.JSON;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import javax.annotation.PostConstruct;
/**
* super_dev_007 2020/11/26
*/
@Component
public class RedisApiUtils{
@Value("${spring.redis.host}")
String host;
@Value("${spring.redis.port}")
int port;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
@Value("${spring.redis.jedis.pool.max-wait}")
private long maxWaitMillis;
@Autowired
RedisSessionDAO redisSessionDAO;
@Autowired
JedisPool jedisPool;
Jedis jedis;
public static String pre = "re_";
@Bean
public JedisPool redisPoolFactory() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout);
return jedisPool;
}
private static RedisApiUtils staticInstance = new RedisApiUtils();
@PostConstruct
public void init(){
staticInstance.redisSessionDAO = redisSessionDAO;
staticInstance.jedisPool = jedisPool;
staticInstance.jedis = jedisPool.getResource();
}
public static Object get(String key){
String value = staticInstance.jedis.get(pre+key);
return JSON.parseObject(value);
}
public static void save(String key,Object value){
staticInstance.jedis.set(pre+key,JSON.toJSONString(value));
}
public static void del(String key){
staticInstance.jedis.del(pre+key);
}
}
最后是登录方法:
@RequestMapping(value = "login")
@ResponseBody
public Object login(@ModelAttribute("user") LoginUser user, HttpServletRequest request, Model model, HttpSession session) {
BaseResp resp = new BaseResp();
String access_token = "" + IdUtils.id();
JSONObject jsonObject = new JSONObject();
/**
* 使用Shiro编写认证操作
*/
try {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),
CommonUtils.md5(user.getPassword()),user.getRememberMe());
subject.login(token);
AdminUserPo adminUserPo = ShiroUtils.getUserEntity();
jsonObject.put("access_token", access_token);
jsonObject.put("user", rtnUser(adminUserPo));
resp.setData(jsonObject);
model.addAttribute("user",adminUserPo);
} catch (UnknownAccountException e) {
resp.setSuccess(false);
resp.setMsg(e.getMessage());
} catch (IncorrectCredentialsException e) {
resp.setSuccess(false);
resp.setMsg(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
resp.setSuccess(false);
resp.setMsg("系统异常,请稍后再试");
}
return resp;
}