环境 SpringBoot2.0
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency>
ShiroConfig
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.mgt.SecurityManager; 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.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { System.out.println("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //拦截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); // 配置不会被拦截的url 顺序判断 //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/dologin", "anon"); filterChainDefinitionMap.put("/logout", "anon"); //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> filterChainDefinitionMap.put("/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/login"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); //未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * 凭证匹配器 * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 * ) * @return */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(1);//散列的次数,比如散列两次,相当于 md5(md5("")); return hashedCredentialsMatcher; } @Bean public MyShiroRealm myShiroRealm(){ MyShiroRealm myShiroRealm = new MyShiroRealm(); myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myShiroRealm; } @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } /** * 开启shiro aop注解支持. * 使用代理方式;所以需要开启代码支持; * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } }
自定义一个MyShiroRealm
import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.crypto.hash.SimpleHash; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; public class MyShiroRealm extends AuthorizingRealm { /*认证 主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //把AuthenticationToken转换成UsernamePasswordToken UsernamePasswordToken usernamePasswordToken=(UsernamePasswordToken)authenticationToken; //获取username String username=usernamePasswordToken.getUsername(); //根据username从数据库查询信息(注入并调用UserService方法),此处省略 //根据获取的用户信息,决定是否抛出AuthenticationException异常,此处写死 if(username.equals("unknown")){ throw new UnknownAccountException("用户不存在!"); } if (username.equals("lock")) { throw new LockedAccountException("用户被锁定!"); } //构建并返回AuthenticationInfo,通常是SimpleAuthenticationInfo //principal:可以是username,也可以是用户实体对象 //credentials:从数据库获取的密码 //realmName:当前realm对象的name Object principal=username; //Object credentials="123456"; Object credentials=new SimpleHash("MD5", "123456", "", 1); String realmName=this.getName(); SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(principal, credentials, realmName); return info; } /** * 授权 权限信息,包括角色以及权限 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()"); SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //如果身份认证的时候没有传入User对象,这里只能取到userName //也就是SimpleAuthenticationInfo构造的时候第一个参数传递需要User对象 String userName = (String)principalCollection.getPrimaryPrincipal(); //根据username从数据库查询角色和权限信息,此处省略 //构造角色数据 if(userName.equals("zhangsan")){ authorizationInfo.addRole("role1"); authorizationInfo.addRole("role2"); } if(userName.equals("lisi")){ authorizationInfo.addRole("role1"); } //构造权限数据 if(userName.equals("zhangsan")){ authorizationInfo.addStringPermission("user:list"); authorizationInfo.addStringPermission("user:add"); authorizationInfo.addStringPermission("user:delete"); } if(userName.equals("lisi")){ authorizationInfo.addStringPermission("user:list"); } return authorizationInfo; } public static void main(String[] args) { String algorithmName="MD5"; String source="123456"; String salt=""; int hashIterations=1; Object result=new SimpleHash(algorithmName, source, salt, hashIterations); System.out.println(result); } }
ShiroTestController 模拟登陆后访问url测试
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.UnauthorizedException; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.subject.Subject; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("") public class ShiroTestController { @RequestMapping(value = "/dologin") public String login() { System.out.println("------登录-------"); String msg = ""; //String username = "zhangsan"; String username = "lisi"; String password = "123456"; UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); try { subject.login(token); if (subject.isAuthenticated()) { return "登录成功"; } else { return "登录失败"; } } catch (IncorrectCredentialsException e) { msg = "登录密码错误. Password for account " + token.getPrincipal() + " was incorrect."; System.out.println(msg); } catch (ExcessiveAttemptsException e) { msg = "登录失败次数过多"; System.out.println(msg); } catch (LockedAccountException e) { msg = "帐号已被锁定. The account for username " + token.getPrincipal() + " was locked."; System.out.println(msg); } catch (DisabledAccountException e) { msg = "帐号已被禁用. The account for username " + token.getPrincipal() + " was disabled."; System.out.println(msg); } catch (ExpiredCredentialsException e) { msg = "帐号已过期. the account for username " + token.getPrincipal() + " was expired."; System.out.println(msg); } catch (UnknownAccountException e) { msg = "帐号不存在. There is no user with username of " + token.getPrincipal(); System.out.println(msg); } catch (UnauthorizedException e) { msg = "您没有得到相应的授权!" + e.getMessage(); System.out.println(msg); } return "登录"; } @RequestMapping(value = "logout", method = RequestMethod.GET) public String logout() { System.out.println("------退出-------"); Subject subject = SecurityUtils.getSubject(); if (subject != null) { try{ subject.logout(); }catch(Exception ex){ } } return "退出成功"; } @RequestMapping("/index") public String index(){ System.out.println("------进入首页-------"); return "进入首页"; } @RequestMapping("/unauthorized") public String unauthorized(){ System.out.println("------未授权-------"); return "未授权"; } @RequestMapping("/userList") @RequiresPermissions("user:list") public String userList(){ System.out.println("------用户列表-------"); return "用户列表"; } @RequestMapping("/userAdd") @RequiresPermissions("user:add") public String userAdd(){ System.out.println("------用户添加-------"); return "用户添加"; } @RequestMapping("/userDelete") @RequiresPermissions("user:delete") public String userDelete(){ System.out.println("------用户删除-------"); return "用户删除"; } }