簡單的五張表,用戶、角色、權限及關聯表:html
CREATE TABLE `sysrole` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `name` varchar(255) NOT NULL, `role` varchar(255) NOT NULL COMMENT '角色名', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='角色表'; CREATE TABLE `sysuser` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `username` varchar(250) NOT NULL, `password` varchar(250) NOT NULL, `salt` varchar(250) NOT NULL COMMENT '密碼鹽', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用戶表'; CREATE TABLE `user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `role_id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='用戶角色表'; CREATE TABLE `syspermission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(250) NOT NULL COMMENT '權限名稱', `type` int(1) NOT NULL COMMENT '權限類型,1菜單menu,2按鈕button,3數據data', `permission` varchar(250) NOT NULL COMMENT '權限表達式', `parent_id` int(11) NOT NULL COMMENT '父級ID', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COMMENT='權限表'; CREATE TABLE `role_permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_id` int(11) NOT NULL, `permission_id` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8 COMMENT='角色權限表';
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-guice</artifactId> <version>1.3.2</version> </dependency>
import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.SessionListener; import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler; import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; 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.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; 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 at.pollux.thymeleaf.shiro.dialect.ShiroDialect; @Configuration public class ShiroConfig { private static Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //緩存管理器 @Bean(name = "cacheShiroManager") public EhCacheManager getCacheManager(){ return new EhCacheManager(); } //生命週期處理器 @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){ return new LifecycleBeanPostProcessor(); } //hash加密處理 @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher getHashedCredentialsMatcher(){ HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("MD5"); credentialsMatcher.setHashIterations(2);//散列的次數,好比散列兩次,至關於 md5(md5("")); credentialsMatcher.setStoredCredentialsHexEncoded(true); return credentialsMatcher; } //瀏覽器會話的cookie管理 @Bean(name = "sessionIdCookie") public SimpleCookie getSessionIdCookie(){ SimpleCookie cookie = new SimpleCookie("sid"); cookie.setHttpOnly(true); cookie.setMaxAge(-1);//瀏覽器關閉時失效此Cookie; return cookie; } //記住個人cookie管理 @Bean(name = "rememberMeCookie") public SimpleCookie getRememberMeCookie(){ SimpleCookie cookie = new SimpleCookie("rememberMe"); //若是httyOnly設置爲true,則客戶端不會暴露給客戶端腳本代碼,使用HttpOnly cookie有助於減小某些類型的跨站點腳本攻擊; cookie.setHttpOnly(true); cookie.setMaxAge(2592000);//記住個人cookie有效期30天 return cookie; } //記住我cookie管理器 @Bean public CookieRememberMeManager getRememberManager(){ CookieRememberMeManager meManager = new CookieRememberMeManager(); meManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag==")); meManager.setCookie(getRememberMeCookie()); return meManager; } //session驗證管理器 @Bean(name = "sessionValidationScheduler") public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler(){ ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler(); //設置session驗證時間,15分鐘一次 scheduler.setInterval(900000); return scheduler; } @Bean(name = "sessionManager") public DefaultWebSessionManager getSessionManage(){ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setGlobalSessionTimeout(1800000);//過時時間30分鐘 //session按期驗證 sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler()); sessionManager.setDeleteInvalidSessions(true); //會話cookie sessionManager.setSessionIdCookie(getSessionIdCookie()); sessionManager.setSessionIdCookieEnabled(true); sessionManager.setSessionValidationSchedulerEnabled(true); //session監聽 LinkedList<SessionListener> list = new LinkedList<SessionListener>(); list.add(new MyShiroSessionListener()); sessionManager.setSessionListeners(list); //session的存儲 EnterpriseCacheSessionDAO cacheSessionDAO = new EnterpriseCacheSessionDAO(); sessionManager.setCacheManager(getCacheManager()); sessionManager.setSessionDAO(cacheSessionDAO); return sessionManager; } @Bean(name = "myRealm") public AuthorizingRealm getShiroRealm(){ AuthorizingRealm realm = new MyShiroRealm(getCacheManager(),getHashedCredentialsMatcher()); realm.setName("my_shiro_auth_cache"); // realm.setAuthenticationCache(getCacheManager().getCache(realm.getName())); realm.setAuthenticationTokenClass(UsernamePasswordToken.class); realm.setCredentialsMatcher(getHashedCredentialsMatcher()); return realm; } @Bean(name = "securityManager") public DefaultWebSecurityManager getSecurityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setCacheManager(getCacheManager()); securityManager.setRealm(getShiroRealm()); securityManager.setRememberMeManager(getRememberManager()); securityManager.setSessionManager(getSessionManage()); return securityManager; } @Bean public MethodInvokingFactoryBean getMethodInvokingFactoryBean(){ MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean(); factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager"); factoryBean.setArguments(new Object[]{getSecurityManager()}); return factoryBean; } @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator getAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } @Bean public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(){ AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(getSecurityManager()); return advisor; } @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(){ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean(); factoryBean.setSecurityManager(getSecurityManager()); //設置登陸頁面路徑 factoryBean.setLoginUrl("/login"); //設置登陸成功跳轉的路徑,此方法有bug // factoryBean.setSuccessUrl("/manager/hello"); //將無需攔截的方法及頁面使用anon配置 filterChainDefinitionMap.put("", "anon"); //將需認證的方法及頁面使用authc配置 filterChainDefinitionMap.put("", "authc");
factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return factoryBean; } @Bean(name = "shiroDialect") public ShiroDialect shiroDialect(){ return new ShiroDialect(); } }
import javax.annotation.Resource; import org.apache.log4j.Logger; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import org.thymeleaf.util.StringUtils; public class MyShiroRealm extends AuthorizingRealm { //注入查詢用戶信息的service層 @Resource private IAuthorityService authorityService; private Logger log = Logger.getLogger(MyShiroRealm.class); public MyShiroRealm(CacheManager cacheManager, CredentialsMatcher matcher) { super(cacheManager, matcher); } //受權 @Override protected AuthorizationInfo doGetAuthorizationInfo( PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); SysUser user = (SysUser) principals.getPrimaryPrincipal(); for(SysRole role:user.getRoleList()){ authorizationInfo.addRole(role.getRole()); for(SysPermission p:role.getPermissions()){ authorizationInfo.addStringPermission(p.getPermission()); } } return authorizationInfo; } //認證 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken user = (UsernamePasswordToken) token; String username = user.getUsername(); String password = user.getPassword().toString(); user.isRememberMe(); if(StringUtils.isEmpty(username)){ throw new IncorrectCredentialsException("username is null"); }else if(StringUtils.isEmpty(password)){ throw new IncorrectCredentialsException("password is null"); } //根據帳戶名稱查詢用戶信息 SysUser sysUser = authorityService.findByUsername(username); if(sysUser == null){ log.error("用戶不存在"+username); return null; }
//密碼加密策略可自定義,此處使用自定義的密碼鹽CredentialsSalt
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(sysUser,sysUser.getPassword(), ByteSource.Util.bytes(sysUser.getCredentialsSalt()),getName());
return authenticationInfo;
}
}
import org.apache.log4j.Logger; import org.apache.shiro.session.Session; import org.apache.shiro.session.SessionListener; public class MyShiroSessionListener implements SessionListener { private Logger log = Logger.getLogger(MyShiroSessionListener.class); @Override public void onStart(Session session) { log.info("----會話建立:"+session.getId()); } @Override public void onStop(Session session) { log.info("----會話中止:"+session.getId()); } @Override public void onExpiration(Session session) { log.info("----會話過時:"+session.getId()); } }
@RequiresAuthentication,認證經過可訪問java
@RequiresPermissions("***"),有***權限可訪問web
@RequiresGuest,遊客便可訪問spring
@RequiresRoles("***"),有***角色可訪問數據庫
@RequiresUser("***"),是***用戶可訪問apache
thyemleaf模板引入shiro標籤庫瀏覽器
<html xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">緩存
<shiro:guest/> <shiro:user/> <shiro:principal/> <shiro:hasPermission/> <shiro:lacksPermission/> <shiro:hasRole/> <shiro:lacksRole/> <shiro:hasAnyRoles/> <shiro:authenticated/> <shiro:notAuthenticated/>
使用方法參考:shiro官網cookie