shiro是一款权限控制的后台框架,能够控制用户-角色-权限的分配,例如资源和路径等等。html
主要内容:java
ShiroFilterFactoryBean工厂类mysql
SecurityManager安全管理器web
MyRealm extends AuthorizingRealm自定义Realm,实现doGetAuthenticationInfo(认证)和doGetAuthorizationInfo(受权)方法。spring
还有其余一些rememberMe、Session和Cache功能。sql
下面使用SpringBoot整合Shiro的例子简单说明apache
表:数据中用户密码要存储加密后的密文安全
pom.xml文件cookie
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>online.myson</groupId> <artifactId>shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Shiro</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!-- Spring Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> <version>2.0.1.RELEASE</version> </dependency> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
shiro配置类app
package online.myson.config; import java.util.LinkedHashMap; import java.util.Map; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.crypto.hash.SimpleHash; 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.util.ByteSource; import org.apache.shiro.web.mgt.CookieRememberMeManager; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import online.myson.shiro.MyRealm; @Configuration public class ShiroConfig { /** * 注册ShiroFilterFactoryBean,实际上是注册一个filter */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 设置securityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 设置拦截器 Map<String,String> filterChainDefinitionMap = new LinkedHashMap<>(); // 过滤链定义,从上向下执行,通常将/**放最下面 // authc:全部的url都必须认证经过才能够访问;anon:全部url均可以匿名访问 filterChainDefinitionMap.put("/statics/**", "anon"); filterChainDefinitionMap.put("/login.html", "anon"); filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/user/**", "user"); filterChainDefinitionMap.put("/*", "authc"); // 不设置自动寻找根目录下的/login.jsp页面 shiroFilterFactoryBean.setLoginUrl("/index"); // 登陆成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); // 未受权页面 shiroFilterFactoryBean.setUnauthorizedUrl("/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * 注册securityManager */ @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm()); securityManager.setRememberMeManager(cookieRememberMeManager()); return securityManager; } /** * 注册自定义Realm */ @Bean public MyRealm myRealm() { MyRealm myRealm = new MyRealm(); myRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myRealm; } /** * 注册HashedCredentialsMatcher,加解密 */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5"); hashedCredentialsMatcher.setHashIterations(2); return hashedCredentialsMatcher; } /** * 注册CookieRememberMeManager */ @Bean public CookieRememberMeManager cookieRememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(simpleCookie()); return cookieRememberMeManager; } /** * 注册SimpleCookie */ @Bean public SimpleCookie simpleCookie() { SimpleCookie simpleCookie = new SimpleCookie(); simpleCookie.setPath("/"); simpleCookie.setHttpOnly(true); simpleCookie.setMaxAge(604800);// 时间 return simpleCookie; } /** * 开启shiro aop支持 * 用于受权 */ @Bean public AuthorizationAttributeSourceAdvisor AuthorizationAttributeSourceAdvisor( SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } public static void main(String[] args) { Object obj = new SimpleHash("md5","123456",ByteSource.Util.bytes("user"),2); System.out.println(obj); } }
一、认证
// 认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 获取用户输入的帐号 String username = (String)token.getPrincipal(); System.out.println(token.getCredentials()); // 查询是否存在帐号 SysUser user = sysUserService.findByUsername(username); System.out.println(user); if(user == null) { return null; } // 验证密码 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()),// salt "MyRealm"// realmName ); return authenticationInfo; }
Controller类:
@PostMapping("/login") public ModelAndView login(SysUser user) { ModelAndView mv = new ModelAndView("/login"); String msg = "成功"; Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); try { subject.login(token); }catch(Exception e) { if(e instanceof UnknownAccountException) { msg = "帐户不存在"; }else if(e instanceof IncorrectCredentialsException) { msg = "密码不正确"; }else { msg = e.getMessage(); } } mv.addObject("msg", msg); return mv; }
二、受权
三种方式:
a、经过Subject.isPermitted("userInfo:view")和subject.hasRole("admin")的一些方法,if else来控制
b、经过注解AOP控制
c、jsp页面使用标签<shiro>控制
// 受权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); SysUser user = (SysUser) principals.getPrimaryPrincipal(); // 获取用户的角色和对应的权限,这里一次性查角色和权限了,也能够写sql查 for(SysRole role : user.getRoleList()) { authorizationInfo.addRole(role.getRole()); for(SysPermission permission : role.getPermissions()) { authorizationInfo.addStringPermission(permission.getPermission()); } } return authorizationInfo; }
Controller:
/** * 用户添加 */ @GetMapping("/user/add") @RequiresPermissions("userInfo:view") public String userAdd() { Subject subject = SecurityUtils.getSubject(); // if(subject.isPermitted("userInfo:view")) { // return "userAdd"; // }else { // return "no authc"; // } return "userAdd";