springboot整合shiro进行身份验证和授权
一、引入shiro依赖:
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <groupId>com.shiro</groupId> 5 <artifactId>wangyao</artifactId> 6 <packaging>war</packaging> 7 <version>0.0.1-SNAPSHOT</version> 8 <name>wangyao Maven Webapp</name> 9 <url>http://maven.apache.org</url> 10 <!--启动父依赖 --> 11 <parent> 12 <groupId>org.springframework.boot</groupId> 13 <artifactId>spring-boot-starter-parent</artifactId> 14 <version>1.5.6.RELEASE</version> 15 </parent> 16 <properties> 17 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 18 <java.version>1.8</java.version> 19 <sqlserver-connector>4.0</sqlserver-connector> 20 </properties> 21 <dependencies> 22 <!--spring 基本的web服务 --> 23 <dependency> 24 <groupId>org.springframework.boot</groupId> 25 <artifactId>spring-boot-starter-web</artifactId> 26 </dependency> 27 <!--thmleaf模板依赖. --> 28 <dependency> 29 <groupId>org.springframework.boot</groupId> 30 <artifactId>spring-boot-starter-thymeleaf</artifactId> 31 </dependency> 32 <!-- shiro spring. --> 33 <dependency> 34 <groupId>org.apache.shiro</groupId> 35 <artifactId>shiro-spring</artifactId> 36 <version>1.3.2</version> 37 </dependency> 38 <!-- Spirng data JPA依赖; --> 39 <dependency> 40 <groupId>org.springframework.boot</groupId> 41 <artifactId>spring-boot-starter-data-jpa</artifactId> 42 </dependency> 43 <!-- sqlserver依赖 --> 44 <dependency> 45 <groupId>com.microsoft.sqlserver</groupId> 46 <artifactId>sqljdbc4</artifactId> 47 <version>${sqlserver-connector}</version> 48 </dependency> 49 <dependency> 50 <groupId>org.springframework.boot</groupId> 51 <artifactId>spring-boot-devtools</artifactId> 52 <optional>true</optional> 53 </dependency> 54 <dependency> 55 <groupId>junit</groupId> 56 <artifactId>junit</artifactId> 57 <version>3.8.1</version> 58 <scope>test</scope> 59 </dependency> 60 </dependencies> 61 <build> 62 <finalName>wangyao</finalName> 63 </build> 64 </project>
二、shiro配置:
1 package shiropro.config; 2 3 import java.util.LinkedHashMap; 4 import java.util.Map; 5 6 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; 7 import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 8 import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 9 import org.springframework.context.annotation.Bean; 10 import org.springframework.context.annotation.Configuration; 11 import org.apache.shiro.mgt.SecurityManager; 12 import shiropro.shiro.MyShiroRealm; 13 14 /** 15 * shiro配置 16 * 17 * @author wangyao 18 * 19 */ 20 @Configuration 21 public class ShiroConfiguration { 22 @Bean 23 public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { 24 System.err.println("ShiroConfiguration.shirFilter()"); 25 ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 26 // 必须设置 SecurityManager 27 shiroFilterFactoryBean.setSecurityManager(securityManager); 28 // 拦截器. 29 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); 30 31 // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 32 shiroFilterFactoryBean.setLoginUrl("/login"); 33 // 登录成功后要跳转的链接 34 shiroFilterFactoryBean.setSuccessUrl("/index"); 35 // 未授权界面; 36 shiroFilterFactoryBean.setUnauthorizedUrl("/403"); 37 38 // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了 39 filterChainDefinitionMap.put("/logout", "logout"); 40 filterChainDefinitionMap.put("/add", "perms[权限添加]"); 41 filterChainDefinitionMap.put("/del", "perms[权限删除]"); 42 // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; 43 // <!-- authc 表示需要认证才能访问的页面 --> 44 filterChainDefinitionMap.put("/**", "authc"); 45 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); 46 System.out.println("Shiro拦截器工厂类注入成功"); 47 return shiroFilterFactoryBean; 48 } 49 50 /** 51 * 身份认证realm; (这个需要自己写,账号密码校验;权限等) 52 * 53 * @return 54 */ 55 @Bean 56 public MyShiroRealm myShiroRealm() { 57 MyShiroRealm myShiroRealm = new MyShiroRealm(); 58 return myShiroRealm; 59 } 60 61 @Bean 62 public SecurityManager securityManager() { 63 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 64 // 设置realm. 65 securityManager.setRealm(myShiroRealm()); 66 return securityManager; 67 } 68 69 /** 70 * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持,调用授权的方法必须要有此支持; 71 * 72 * @param securityManager 73 * @return 74 */ 75 76 @Bean 77 public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { 78 AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); 79 authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); 80 return authorizationAttributeSourceAdvisor; 81 } 82 83 }
三、shiro身份校验(继承AuthorizingRealm):
1 package shiropro.shiro; 2 3 4 import java.util.HashSet; 5 import java.util.Map; 6 import java.util.Set; 7 8 import javax.annotation.Resource; 9 10 import org.apache.shiro.authc.AuthenticationException; 11 import org.apache.shiro.authc.AuthenticationInfo; 12 import org.apache.shiro.authc.AuthenticationToken; 13 import org.apache.shiro.authc.SimpleAuthenticationInfo; 14 import org.apache.shiro.authc.UsernamePasswordToken; 15 import org.apache.shiro.authz.AuthorizationInfo; 16 import org.apache.shiro.authz.SimpleAuthorizationInfo; 17 import org.apache.shiro.realm.AuthorizingRealm; 18 import org.apache.shiro.subject.PrincipalCollection; 19 20 import shiropro.entity.UserInfo; 21 import shiropro.service.IUserInfoService; 22 /** 23 * shiro身份校验 24 * 25 * @author wangyao 26 * 27 */ 28 public class MyShiroRealm extends AuthorizingRealm { 29 30 @Resource 31 private IUserInfoService userInfoService; 32 33 /** 34 * 认证信息.(身份验证) : Authentication 是用来验证用户身份 35 * 36 * @param token 37 * @return 38 * @throws AuthenticationException 39 */ 40 @Override 41 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 42 System.err.println("MyShiroRealm.doGetAuthenticationInfo()"); 43 UsernamePasswordToken tk=(UsernamePasswordToken) token; 44 // 获取用户的输入的账号. 45 String username = tk.getUsername(); 46 //获取用户输入的密码 47 //String pwd=new String(token.getPassword()); 48 // 实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法 49 UserInfo userInfo = userInfoService.findByUsername(username); 50 //密码可以加密在此 51 System.out.println("----->>userInfo=" + userInfo); 52 if (userInfo == null) { 53 return null; 54 } 55 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userInfo, // 用户名 56 userInfo.getPassword(), // 密码 57 getName() // realm name 58 ); 59 60 return authenticationInfo; 61 } 62 /** 63 * 获取授权信息(包含权限信息) 64 */ 65 @Override 66 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) { 67 UserInfo user=(UserInfo) getAvailablePrincipal(pc); 68 System.err.println("授权:"+user); 69 String loginName= user.getUsername(); 70 if (loginName != null) { 71 SimpleAuthorizationInfo info=new SimpleAuthorizationInfo(); 72 Map<String,Object> map=user.getPerList(); 73 //用户的角色信息 74 /*List<String> roles=(List<String>) map.get("roles"); 75 for (String role : roles) { 76 info.addRole(role); 77 }*/ 78 Set<String> roleSet=new HashSet<String>(); 79 roleSet.add("100002"); 80 info.setRoles(roleSet); 81 //用户的权限信息 82 /*List<String> permissions=(List<String>) map.get("permissions"); 83 for (String permission : permissions) { 84 info.addStringPermission(permission); 85 }*/ 86 Set<String> permissionSet =new HashSet<String>(); 87 permissionSet.add("权限添加"); 88 info.setStringPermissions(permissionSet); 89 return info; 90 } 91 return null; 92 } 93 94 95 }
四、控制层:
package shiropro.action; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HomeAction { @GetMapping("/index") public String index() { return "index"; } @PostMapping("/del") public String del() { return "del"; } @PostMapping("/add") public String add() { return "add"; } @GetMapping("/login") public String lo() { return "login"; } // 登录提交地址和applicationontext-shiro.xml配置的loginurl一致。 (配置文件方式的说法) @PostMapping("/login") public String login(HttpServletRequest request, Map<String, Object> map) throws Exception { System.out.println("HomeController.login()"); // 登录失败从request中获取shiro处理的异常信息。//也可以自定义判断 // shiroLoginFailure:就是shiro异常类的全类名. String exception = (String) request.getAttribute("shiroLoginFailure"); System.out.println("exception=" + exception); String msg = ""; if (exception != null) { if (UnknownAccountException.class.getName().equals(exception)) { System.out.println("UnknownAccountException -- > 账号不存在:"); msg = "UnknownAccountException -- > 账号不存在:"; } else if (IncorrectCredentialsException.class.getName().equals(exception)) { System.out.println("IncorrectCredentialsException -- > 密码不正确:"); msg = "IncorrectCredentialsException -- > 密码不正确:"; } else if ("kaptchaValidateFailed".equals(exception)) { System.out.println("kaptchaValidateFailed -- > 验证码错误"); msg = "kaptchaValidateFailed -- > 验证码错误"; } else { msg = "else >> " + exception; System.out.println("else -- >" + exception); } } map.put("msg", msg); // 此方法不处理登录成功,由shiro进行处理. return "index"; } //----------------------------------------------------------------------------------------------------------- public static void main(String[] args) { List<Integer> a = new ArrayList<>(); List<Integer> b = new ArrayList<>(); for (int i = 0; i < 100000; i++) { if (i % 2 == 0) { a.add(i); } if (i % 3 == 0) { b.add(i); } } List<Integer> list = new ArrayList<>(); Map<String, Object> map = new HashMap<>(); System.out.println("a.size:" + a.size() + ".....b.size:" + b.size()); long s = System.currentTimeMillis(); // for (Integer i : a) { // map.put(i.toString(), i); // } // System.out.println(map.size()); // for (Integer in : b) { // if(map.get(in.toString())!=null){ // list.add(in); // } // } // list.addAll(a);list.addAll(b); System.out.println("-------list:" + list.size()); System.out.println("------------------"); // List<Integer> list2=new ArrayList<>(); // Set<Integer> set=new HashSet<>(); // set.addAll(list); // for (Integer integer : set) { // list2.add(integer); // } // System.out.println("-------list2:"+list2.size()); // list.removeAll(list2); // System.out.println("----------------0"); for (Integer m : a) { //if (m <= 1000) { if (m % 3 == 0) { list.add(m); } //} } long e = System.currentTimeMillis(); System.out.println(e - s + "......." + list.size()); } }
五、login页面:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Insert title here</title> </head> <body> 错误信息: <h4 th:text="${msg}"></h4> <form action="/login" method="post"> <p> 账号:<input type="text" name="username" value="admin" /> </p> <p> 密码:<input type="text" name="password" value="123456" /> </p> <p> <input type="submit" value="登录" /> </p> </form> </body> </html>
2017-09-01 15:39:45