1.新建 CustomRealm 類 重新doGetAuthenticationInfo方法
package com.alpha.shiro.realm; import com.alpha.model.system.User; import com.alpha.service.system.PermissionService; import com.alpha.service.system.UserService; import org.apache.shiro.SecurityUtils; 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.springframework.beans.factory.annotation.Autowired; import java.util.HashSet; import java.util.List; import java.util.Set; /** * 描述: * * @author caojing * @create 2019-01-27-13:57 */ public class CustomRealm extends AuthorizingRealm { @Autowired UserService userService; @Autowired PermissionService permissionService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String username = (String) SecurityUtils.getSubject().getPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); List<String> allPermission = permissionService.getPermissionImp(username); Set<String> stringSet = new HashSet<>(allPermission); info.setStringPermissions(stringSet); return info; } /** * 這里可以注入userService,為了方便演示,我就寫死了帳號了密碼 * private UserService userService; * <p> * 獲取即將需要認證的信息 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("-------身份認證方法--------"); String userName = (String) authenticationToken.getPrincipal(); String userPwd = new String((char[]) authenticationToken.getCredentials()); //根據用戶名從數據庫獲取密碼 User u = userService.login(userPwd,userName); if (u == null) { throw new AccountException("賬號或密碼錯誤"); } return new SimpleAuthenticationInfo(userName, userPwd,getName()); } }
2.新建 CustomSessionManager 重寫 getSessionId方法
package com.alpha.shiro.session; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.apache.shiro.web.util.WebUtils; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import java.io.Serializable; /** * @version: 1.0 * @since: JDK 1.8.0_91 * @Description: 適用於前后端分離情況下對sessionId的獲取 * * <br>Modification History:<br> * Date | Author | Version | Description<br> * ------------------------------------------------------------------<br> * 2018年10月23日 | yao_x_x | 1.0 | 1.0 Version */ public class CustomSessionManager extends DefaultWebSessionManager { /** * 獲取請求頭中key為“Authorization”的value == sessionId */ private static final String AUTHORIZATION ="Authorization"; private static final String REFERENCED_SESSION_ID_SOURCE = "cookie"; /** * @Description shiro框架 自定義session獲取方式<br/> * 可自定義session獲取規則。這里采用ajax請求頭 {@link }攜帶sessionId的方式 */ @Override protected Serializable getSessionId(ServletRequest request, ServletResponse response) { // TODO Auto-generated method stub String sessionId = WebUtils.toHttp(request).getHeader(AUTHORIZATION); if (StringUtils.isNotEmpty(sessionId)) { request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); return sessionId; } return super.getSessionId(request, response); } }
3.新建 ShiroConfig 類,重點實現SessionDAO
package com.alpha.shiro.config; import com.alpha.redis.sso.dao.RedisSessionDao; import com.alpha.shiro.realm.CustomRealm; import com.alpha.shiro.session.CustomSessionManager; import org.apache.shiro.session.mgt.SessionManager; 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.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; 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; /** * 描述: * * @author caojing * @create 2019-01-27-13:38 */ @Configuration public class ShiroConfig { @Value("${spring.system.login-url}") private String loginUrl; /** * Shiro生命周期處理器 */ @Bean(name = "lifecycleBeanPostProcessor") public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 開啟Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP掃描使用Shiro注解的類,並在必要時進行安全邏輯驗證 */ @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } /** * 開啟aop注解支持 * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(org.apache.shiro.mgt.SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean("securityManager") public org.apache.shiro.mgt.SecurityManager securityManager(@Qualifier("sessionManager")SessionManager sessionManager) { DefaultWebSecurityManager manager = new DefaultWebSecurityManager(); manager.setRealm(customRealm()); manager.setSessionManager(sessionManager); return manager; } @Bean public RedisSessionDao getRedisSessionDao(){ return new RedisSessionDao(); } @Bean("sessionManager") public SessionManager sessionManager(){ CustomSessionManager manager = new CustomSessionManager(); /*使用了shiro自帶緩存, 如果設置 redis為緩存需要重寫CacheManager(其中需要重寫Cache) */ manager.setSessionDAO(getRedisSessionDao()); return manager; } @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(org.apache.shiro.mgt.SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl(loginUrl); shiroFilterFactoryBean.setUnauthorizedUrl(loginUrl); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // <!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問--> filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/admin/user/**", "anon"); filterChainDefinitionMap.put("/unAuth", "anon"); filterChainDefinitionMap.put("/login.html", "anon"); filterChainDefinitionMap.put("/admin/home/login", "anon"); filterChainDefinitionMap.put("/admin/website/getInfo", "anon"); filterChainDefinitionMap.put("/swagger-ui.html", "anon"); filterChainDefinitionMap.put("/swagger-resources/**", "anon"); filterChainDefinitionMap.put("/v2/api-docs", "anon"); filterChainDefinitionMap.put("/webjars/springfox-swagger-ui/**", "anon"); filterChainDefinitionMap.put("/unAuth.html", "anon"); // filterChainDefinitionMap.put("/user/**", "authc"); //主要這行代碼必須放在所有權限設置的最后,不然會導致所有 url 都被攔截 剩余的都需要認證 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public CustomRealm customRealm() { CustomRealm customRealm = new CustomRealm(); return customRealm; } }
4,實現 SessionDAO 新建 RedisSessionDao
package com.alpha.redis.sso.dao; import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import java.io.Serializable; import java.util.Collection; import java.util.concurrent.TimeUnit; /** * Created by Administrator on 2018/7/31. */ @Service public class RedisSessionDao extends AbstractSessionDAO { // Session超時時間,單位為毫秒 private long expireTime = 120000; @Autowired private RedisTemplate redisTemplate;// Redis操作類,對這個使用不熟悉的,可以參考前面的博客 public RedisSessionDao() { super(); } public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) { super(); this.expireTime = expireTime; this.redisTemplate = redisTemplate; } @Override // 更新session public void update(Session session) throws UnknownSessionException { System.out.println("===============update================"); if (session == null || session.getId() == null) { return; } session.setTimeout(expireTime); redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS); } @Override // 刪除session public void delete(Session session) { System.out.println("===============delete================"); if (null == session) { return; } redisTemplate.opsForValue().getOperations().delete(session.getId()); } @Override // 獲取活躍的session,可以用來統計在線人數,如果要實現這個功能,可以在將session加入redis時指定一個session前綴,統計的時候則使用keys("session-prefix*")的方式來模糊查找redis中所有的session集合 public Collection<Session> getActiveSessions() { System.out.println("==============getActiveSessions================="); return redisTemplate.keys("*"); } @Override// 加入session protected Serializable doCreate(Session session) { System.out.println("===============doCreate================"); Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS); return sessionId; } @Override// 讀取session protected Session doReadSession(Serializable sessionId) { System.out.println("==============doReadSession================="); if (sessionId == null) { return null; } return (Session) redisTemplate.opsForValue().get(sessionId); } public long getExpireTime() { return expireTime; } public void setExpireTime(long expireTime) { this.expireTime = expireTime; } public RedisTemplate getRedisTemplate() { return redisTemplate; } public void setRedisTemplate(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } }
5.在yml上新增配置
spring: redis: host: 127.0.0.1 port: 6379 database: 0 password:
完成!