SpringBoot 整合Shiro
pom文件, springboot 2.x
1 2 3 4 5 6 | <!--shiro--> < dependency > < groupId >org.apache.shiro</ groupId > < artifactId >shiro-spring</ artifactId > < version >1.4.0</ version > </ dependency > |
ShiroConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | package com.example.shiro.config; import com.example.shiro.realm.UserRealm; import org.apache.shiro.mgt.SecurityManager; 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.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; /** * @Title: ShiroConfig * @ProjectName shiro * @date 2019/8/29:25 */ @Configuration public class ShiroConfig { @Value ( "${shiro.user.loginUrl}" ) public String loginUrl; @Value ( "${shiro.user.unauthorizedUrl}" ) private String unanthorizedUrl; /** * shiro 过滤器 * @param securityManager * @return */ @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // Shiro的核心安全接口,这个属性是必须的 shiroFilterFactoryBean.setSecurityManager(securityManager); // 身份认证失败,则跳转到登录页面的配置 shiroFilterFactoryBean.setLoginUrl(loginUrl); // 权限认证失败,则跳转到指定页面 shiroFilterFactoryBean.setUnauthorizedUrl(unanthorizedUrl); // Shiro连接约束配置,即过滤链的定义,所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访 LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); // 对静态资源设置匿名访问 filterChainDefinitionMap.put( "/favicon.ico**" , "anon" ); filterChainDefinitionMap.put( "/sy.png**" , "anon" ); filterChainDefinitionMap.put( "/css/**" , "anon" ); filterChainDefinitionMap.put( "/docs/**" , "anon" ); filterChainDefinitionMap.put( "/fonts/**" , "anon" ); filterChainDefinitionMap.put( "/img/**" , "anon" ); filterChainDefinitionMap.put( "/ajax/**" , "anon" ); filterChainDefinitionMap.put( "/js/**" , "anon" ); filterChainDefinitionMap.put( "/sy/**" , "anon" ); filterChainDefinitionMap.put( "/druid/**" , "anon" ); filterChainDefinitionMap.put( "/captcha/captchaImage**" , "anon" ); filterChainDefinitionMap.put( "/logout" , "logout" ); // filterChainDefinitionMap.put("/login", "anon,captchaValidate"); filterChainDefinitionMap.put( "/login" , "anon" ); filterChainDefinitionMap.put( "/index" , "anon" ); // 定义filter Map<String, Filter> filters = new LinkedHashMap<String, Filter>(); // filters.put("onlineSession", onlineSessionFilter()); // filters.put("syncOnlineSession", syncOnlineSessionFilter()); // filters.put("captchaValidate", captchaValidateFilter()); // filters.put("kickout", kickoutSessionFilter()); // 注销成功,则跳转到指定页面 // filters.put("logout", logoutFilter()); shiroFilterFactoryBean.setFilters(filters); // 所有请求需要认证 filterChainDefinitionMap.put( "/**" , "user" ); // user 登陆过 // filterChainDefinitionMap.put("/**", "user,kickout,onlineSession,syncOnlineSession"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager(UserRealm userRealm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(userRealm); // 记住我 // securityManager.setRememberMeManager(rememberMeManager()); // 注入缓存管理器; // securityManager.setCacheManager(getEhCacheManager()); // session管理器 // securityManager.setSessionManager(sessionManager()); return defaultWebSecurityManager; } /** * 自定义Realm * EhCacheManager cacheManager */ @Bean public UserRealm userRealm() { UserRealm userRealm = new UserRealm(); // userRealm.setCacheManager(cacheManager); return userRealm; } /** * 开启Shiro注解通知器, 不然使用注解失效 */ @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){ return new LifecycleBeanPostProcessor(); } @Bean @DependsOn ({ "lifecycleBeanPostProcessor" }) public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass( true ); return advisorAutoProxyCreator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } } |
自定义Realm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | package com.example.shiro.realm; 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 java.util.HashSet; import java.util.Set; /** * @Title: UserRealm * @ProjectName shiro * @date 2019/8/29:27 */ public class UserRealm extends AuthorizingRealm { /** * 授权 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String username = (String) SecurityUtils.getSubject().getPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); Set<String> stringSet = new HashSet<>(); stringSet.add( "user:view:add" ); stringSet.add( "user:view:del" ); Set<String> role = new HashSet<>(); role.add( "admin" ); info.setRoles(role); // set 角色 info.setStringPermissions(stringSet); // set 权限 return info; } /** * 每次登陆都会进入此方法,认证 * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println( "-------身份认证方法--------" ); UsernamePasswordToken upToken = (UsernamePasswordToken) token; String userName = upToken.getUsername(); String userPwd = upToken.getPassword() != null ? new String(upToken.getPassword()) : "" ; //根据用户名从数据库获取密码进行对比 String password = "123qwe" ; if (userName == null ) { throw new AccountException( "用户名不正确" ); } else if (!userPwd.equals(password)) { throw new AccountException( "密码不正确" ); } return new SimpleAuthenticationInfo(userName, password, getName()); } } |
设置
1 2 | // 权限认证失败,则跳转到指定页面 shiroFilterFactoryBean.setUnauthorizedUrl(unanthorizedUrl); |
设置跳转页面失败,报错情况增加异常处理即可.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.example.shiro.advice; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.UnauthorizedException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; /** * @Title: NoPermissionException * @ProjectName shiro * @date 2019/8/211:20 */ @ControllerAdvice public class NoPermissionException { @ResponseBody @ExceptionHandler (UnauthorizedException. class ) public String handleShiroException(HttpServletRequest request,UnauthorizedException ex) { return "无权限" ; } @ResponseBody @ExceptionHandler (AuthorizationException. class ) public String AuthorizationException(HttpServletRequest request, AuthorizationException e) { return "权限认证失败" ; } } |
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | package com.example.shiro.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; 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.ResponseBody; /** * @Title: ShiroController * @ProjectName shiro * @date 2019/8/210:20 */ @Controller public class ShiroController { @ResponseBody @GetMapping ( "login" ) public String login() { return "LOGIN" ; } @ResponseBody @PostMapping ( "login" ) public String postLogin(String username,String password) { org.apache.shiro.subject.Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username,password); try { subject.login(token); } catch (Exception e) { return "登陆失败" ; } return "登陆成功" ; } @ResponseBody @RequiresPermissions ( "user:view:add" ) @GetMapping ( "add" ) public String add() { return "add" ; } @ResponseBody @RequiresPermissions ( "user:view:del" ) @GetMapping ( "del" ) public String del() { return "del" ; } @ResponseBody @GetMapping ( "userupdate" ) @RequiresRoles (value = "user" ) public String userupdate() { return "userupdate" ; } @ResponseBody @GetMapping ( "viewselect" ) @RequiresPermissions ( "xxx:xxx:xxx" ) public String select() { return "select" ; } @ResponseBody @RequiresRoles (value = "admin" ) @GetMapping ( "update" ) public String update() { return "update" ; } @ResponseBody @GetMapping ( "unauth" ) public String unauth() { return "unauth 504 没有权限" ; } @ResponseBody @GetMapping ( "loginout" ) public String loginOut() { SecurityUtils.getSubject().logout(); return "loginout" ; } @GetMapping ( "index" ) public String index(){ return "index" ; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义