一、用户认证
1 Subject currentUser = SecurityUtils.getSubject(); 2 UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray()); 3 currentUser.login(token);
二、自定义Realm
/** * 登录认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; User user = 查询数据库; ShiroUser shiroUser = 创建ShiroUser; String credentials = user.getPassword(); // 密码加盐处理 String source = user.getSalt(); ByteSource credentialsSalt = new Md5Hash(source); return new SimpleAuthenticationInfo(shiroUser, credentials, credentialsSalt, realmName); } /** * 权限认证 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal(); List<Integer> roleList = shiroUser.getRoleList(); Set<String> permissionSet = new HashSet<>(); Set<String> roleNameSet = new HashSet<>(); for (Integer roleId : roleList) { List<String> permissions = shiroFactory.findPermissionsByRoleId(roleId); if (permissions != null) { for (String permission : permissions) { if (ToolUtil.isNotEmpty(permission)) { permissionSet.add(permission); } } } String roleName = shiroFactory.findRoleNameByRoleId(roleId); roleNameSet.add(roleName); } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addStringPermissions(permissionSet); info.addRoles(roleNameSet); return info; }
三、Shiro配置
@Configuration public class ShiroConfig { /** * 安全管理器 */ @Bean public DefaultWebSecurityManager securityManager(CookieRememberMeManager rememberMeManager, CacheManager cacheShiroManager, SessionManager sessionManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(this.shiroDbRealm()); securityManager.setCacheManager(cacheShiroManager); securityManager.setRememberMeManager(rememberMeManager); securityManager.setSessionManager(sessionManager); return securityManager; } /** * spring session管理器(多机环境) */ @Bean @ConditionalOnProperty(prefix = "guns", name = "spring-session-open", havingValue = "true") public ServletContainerSessionManager servletContainerSessionManager() { return new ServletContainerSessionManager(); } /** * session管理器(单机环境) */ @Bean @ConditionalOnProperty(prefix = "guns", name = "spring-session-open", havingValue = "false") public DefaultWebSessionManager defaultWebSessionManager(CacheManager cacheShiroManager, GunsProperties gunsProperties) { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setCacheManager(cacheShiroManager); sessionManager.setSessionValidationInterval(gunsProperties.getSessionValidationInterval() * 1000); sessionManager.setGlobalSessionTimeout(gunsProperties.getSessionInvalidateTime() * 1000); sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionValidationSchedulerEnabled(true); Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME); cookie.setName("shiroCookie"); cookie.setHttpOnly(true); sessionManager.setSessionIdCookie(cookie); return sessionManager; } /** * 缓存管理器 使用Ehcache实现 */ @Bean public CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) { EhCacheManager ehCacheManager = new EhCacheManager(); ehCacheManager.setCacheManager(ehcache.getObject()); return ehCacheManager; } /** * 项目自定义的Realm */ @Bean public ShiroDbRealm shiroDbRealm() { return new ShiroDbRealm(); } /** * rememberMe管理器, cipherKey生成见{@code Base64Test.java} */ @Bean public CookieRememberMeManager rememberMeManager(SimpleCookie rememberMeCookie) { CookieRememberMeManager manager = new CookieRememberMeManager(); manager.setCipherKey(Base64.decode("Z3VucwAAAAAAAAAAAAAAAA==")); manager.setCookie(rememberMeCookie); return manager; } /** * 记住密码Cookie */ @Bean public SimpleCookie rememberMeCookie() { SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); simpleCookie.setHttpOnly(true); simpleCookie.setMaxAge(7 * 24 * 60 * 60);//7天 return simpleCookie; } /** * Shiro的过滤器链 */ @Bean public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); /** * 默认的登陆访问url */ shiroFilter.setLoginUrl("/login"); /** * 登陆成功后跳转的url */ shiroFilter.setSuccessUrl("/"); /** * 没有权限跳转的url */ shiroFilter.setUnauthorizedUrl("/global/error"); /** * 覆盖默认的user拦截器(默认拦截器解决不了ajax请求 session超时的问题,若有更好的办法请及时反馈作者) */ HashMap<String, Filter> myFilters = new HashMap<>(); myFilters.put("user", new GunsUserFilter()); shiroFilter.setFilters(myFilters); /** * 配置shiro拦截器链 * * anon 不需要认证 * authc 需要认证 * user 验证通过或RememberMe登录的都可以 * * 当应用开启了rememberMe时,用户下次访问时可以是一个user,但不会是authc,因为authc是需要重新认证的 * * 顺序从上到下,优先级依次降低 * * api开头的接口,走rest api鉴权,不走shiro鉴权 * */ Map<String, String> hashMap = new LinkedHashMap<>(); hashMap.put("/static/**", "anon"); hashMap.put("/gunsApi/**", "anon"); hashMap.put("/login", "anon"); hashMap.put("/global/sessionError", "anon"); hashMap.put("/kaptcha", "anon"); hashMap.put("/**", "user"); shiroFilter.setFilterChainDefinitionMap(hashMap); return shiroFilter; } /** * 在方法中 注入 securityManager,进行代理控制 */ @Bean public MethodInvokingFactoryBean methodInvokingFactoryBean(DefaultWebSecurityManager securityManager) { MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean(); bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager"); bean.setArguments(new Object[]{securityManager}); return bean; } /** * Shiro生命周期处理器: * 用于在实现了Initializable接口的Shiro bean初始化时调用Initializable接口回调(例如:UserRealm) * 在实现了Destroyable接口的Shiro bean销毁时调用 Destroyable接口回调(例如:DefaultSecurityManager) */ @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 启用shrio授权注解拦截方式,AOP式方法级权限检查 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
三、使用自定义注解的方式进行Shiro方法的拦截(此处只粘出了自定义注解的使用和AOP拦截方式,具体的权限检查没有粘出)
@Inherited @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Permission { /** * <p>角色英文名称</p> * <p>使用注解时加上这个值表示限制只有某个角色的才可以访问对应的资源</p> * <p>常用在某些资源限制只有超级管理员角色才可访问</p> */ String[] value() default {}; } /** * AOP 权限自定义检查 */ @Aspect @Component @Order(200) public class PermissionAop { @Pointcut(value = "@annotation(com.stylefeng.guns.core.common.annotion.Permission)") private void cutPermission() { } @Around("cutPermission()") public Object doPermission(ProceedingJoinPoint point) throws Throwable { MethodSignature ms = (MethodSignature) point.getSignature(); Method method = ms.getMethod(); Permission permission = method.getAnnotation(Permission.class); Object[] permissions = permission.value(); if (permissions == null || permissions.length == 0) { //检查全体角色 boolean result = PermissionCheckManager.checkAll(); if (result) { return point.proceed(); } else { throw new NoPermissionException(); } } else { //检查指定角色 boolean result = PermissionCheckManager.check(permissions); if (result) { return point.proceed(); } else { throw new NoPermissionException(); } } } }