<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-all</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.3.2</version> </dependency>
1:建立ShiroConfigBeanweb
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; 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.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ShiroConfigBean { @Bean public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) { System.out.println("初始化攔截器"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必須設置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 攔截器. Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 設置login URL shiroFilterFactoryBean.setLoginUrl("/login"); //遊客,開發權限 filterChainDefinitionMap.put("/guest/**", "anon"); //用戶,須要角色權限 「user」 filterChainDefinitionMap.put("/user/**", "roles[user]"); //管理員,須要角色權限 「admin」 filterChainDefinitionMap.put("/admin/**", "roles[admin]"); //開放登錄接口 filterChainDefinitionMap.put("/login", "anon"); //其他接口一概攔截 //主要這行代碼必須放在全部權限設置的最後,否則會致使全部 url 都被攔截 filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /* * 憑證匹配器 (因爲咱們的密碼校驗交給Shiro的SimpleAuthenticationInfo進行處理了 * 因此咱們須要修改下doGetAuthenticationInfo中的代碼; ) */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { System.out.println("密碼匹配器"); HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:這裏使用MD5算法; hashedCredentialsMatcher.setHashIterations(1);// 散列的次數,好比散列兩次,至關於md5(md5("")); return hashedCredentialsMatcher; } // @Bean public MyShiroRealm myShiroRealm() { System.out.println("進入relam"); MyShiroRealm myShiroRealm = new MyShiroRealm(); myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myShiroRealm; } @Bean public DefaultWebSecurityManager securityManager() { System.out.println("將relam注入到securityManager"); DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 注入自定義的realm; securityManager.setRealm(myShiroRealm()); // 注入緩存管理器; securityManager.setCacheManager(ehCacheManager()); return securityManager; } /* * 開啓shiro aop註解支持 使用代理方式;因此須要開啓代碼支持; */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( DefaultWebSecurityManager securityManager) { System.out.println("開啓註解模式"); AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * DefaultAdvisorAutoProxyCreator,Spring的一個bean,由Advisor決定對哪些類的方法進行AOP代理。 */ @Bean @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator(); defaultAAP.setProxyTargetClass(true); return defaultAAP; } /* * shiro緩存管理器; * 須要注入對應的其它的實體類中-->安全管理器:securityManager可見securityManager是整個shiro的核心; */ @Bean public EhCacheManager ehCacheManager() { System.out.println("shiro緩存"); EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile("classpath:ehcache.xml"); return cacheManager; } }
2:編寫自定義的realm算法
import com.tuyue.entity.User; import com.tuyue.mapper.PermissionMapper; import com.tuyue.mapper.RoleMapper; import com.tuyue.mapper.UserMapper; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; 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.apache.shiro.util.StringUtils; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; /** * realm實現類,用於實現具體的驗證和受權方法 * @author Bean * */ public class MyShiroRealm extends AuthorizingRealm { @Autowired private UserMapper userMapper; @Autowired private RoleMapper roleMapper; @Autowired private PermissionMapper permissionMapper; /** * 方面用於加密 參數:AuthenticationToken是從表單穿過來封裝好的對象 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("開始驗證是否登陸" + token.getPrincipal()); UsernamePasswordToken upToken = (UsernamePasswordToken) token; // 得到從表單傳過來的用戶名 String username = upToken.getUsername(); if(username==null||username.length()==0){ return null; } User user=new User(); user.setUsername(username); User user1 = userMapper.selectOne(user); // 若是用戶不存在,拋此異常 if (user1==null) { throw new UnknownAccountException("無此用戶名!"); } // 認證的實體信息,能夠是username,也能夠是用戶的實體類對象,這裏用的用戶名 Object principal = user1; // 顏值加密的顏,能夠用用戶名 ByteSource credentialsSalt = ByteSource.Util.bytes("222"); // 當前realm對象的名稱,調用分類的getName() String realmName = this.getName(); // 建立SimpleAuthenticationInfo對象,而且把username和password等信息封裝到裏面用戶密碼的比對是Shiro幫咱們完成的 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, user1.getPassword(),credentialsSalt, realmName); return info; } @Bean @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator(); defaultAAP.setProxyTargetClass(true); return defaultAAP; } // 用於受權 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { System.out.println("受權方法執行"); Set<String> roles = new HashSet<>(); Set<String> permissions = new HashSet<>(); User user= (User) principals.getPrimaryPrincipal(); List<String> list = roleMapper.selectByUserId(user.getId()); for (String s : list) { roles.add(s); } List<String> list1 = permissionMapper.selectByuserId(user.getId()); for (String s : list1) { permissions.add(s); } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles); //添加權限 info.setStringPermissions(permissions); return info; } }
3:建立數據庫spring
USE `shiro`; /*Table structure for table `permission` */ DROP TABLE IF EXISTS `permission`; CREATE TABLE `permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `permission_name` varchar(20) DEFAULT NULL, `source` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; /*Data for the table `permission` */ insert into `permission`(`id`,`permission_name`,`source`) values (1,'添加用戶','user:save'),(2,'刪除用戶','user:del'),(3,'修改用戶','user:up'),(4,'添加商品','goods:save'),(5,'修改商品','goods:up'),(6,'刪除商品','goods:del'); /*Table structure for table `permission_role` */ DROP TABLE IF EXISTS `permission_role`; CREATE TABLE `permission_role` ( `permission_id` int(11) DEFAULT NULL, `role_id` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `permission_role` */ insert into `permission_role`(`permission_id`,`role_id`) values (1,1),(2,1),(3,1),(4,2),(5,2),(6,2); /*Table structure for table `role` */ DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_name` varchar(25) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; /*Data for the table `role` */ insert into `role`(`id`,`role_name`) values (1,'用戶管理員'),(2,'商品管理員'); /*Table structure for table `user` */ DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(20) DEFAULT NULL, `password` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; /*Data for the table `user` */ insert into `user`(`id`,`username`,`password`) values (1,'123','c26a263602b986958afab92363c5984f'),(2,'456','456'); /*Table structure for table `user_role` */ DROP TABLE IF EXISTS `user_role`; CREATE TABLE `user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL, `role_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; /*Data for the table `user_role` */ insert into `user_role`(`id`,`user_id`,`role_id`) values (1,1,1),(2,2,2);
4:編寫controller進行測試
(1)先測試登陸數據庫
@RequestMapping("/login") public String loginUser(String username,String password) { UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password); Subject subject = SecurityUtils.getSubject(); try { subject.login(usernamePasswordToken); //完成登陸 boolean aaa = subject.hasRole("用戶管理員"); System.out.println("2222"+aaa); return "登陸成功"; } catch(Exception e) { e.printStackTrace(); return "登錄失敗"; } }
(2) 測試權限apache
@RequestMapping("test") @RequiresAuthentication @RequiresPermissions("user:del") public String test() { Subject subject = SecurityUtils.getSubject(); return "當前對象:"+subject.getPrincipal().toString(); }