shiro
简介
功能
- Authentication:身份认证,登陆,验证用户是不是拥有相应身份
- Authorization:授权,即权限验证
- Session Manger:会话管理,用户登陆后就是一次会话,没退出之前,所有信息都在会话中,会话可以是JavaSe环境,也可以是Web环境
- Crytography:加密
- Caching:缓存
- Concurrency:多线程应用的并发验证,如在一个线程中开启另一个线程,能把权限自动的传播过去
- Testing:测试支持
- Run As:允许一个用户假装为另一个用户进行访问
- Remember Me:记住我
Shiro架构(外部)
- subject:应用代码直接交互的对象。代表当前用户,用户不一定是一个具体的人,是与当前应用交互的任何东西,像网络爬虫,机器人等。与subject的所有交互都委托给SecurityManager。subject是一个门面,SecurityManager才是实际执行者
- SecurityManager:安全管理器。所有与安全相关的操作都会与SecurityManager交互,管理者所有subject,是shiro核心,负责与shiro其他组件交互,相当于SpringMVC中DispacherServlet
- Realm:连接数据
Shiro架构(内部)
入门代码
-
依赖
<dependencies> <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.7.1</version> </dependency> <!-- slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>jcl-over-slf4j</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies>
-
配置文件
[users] # user 'root' with password 'secret' and the 'admin' role root = secret, admin # user 'guest' with the password 'guest' and the 'guest' role guest = guest, guest # user 'presidentskroob' with password '12345' ("That's the same combination on # my luggage!!!" ;)), and role 'president' presidentskroob = 12345, president # user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz' darkhelmet = ludicrousspeed, darklord, schwartz # user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz' lonestarr = vespa, goodguy, schwartz # ----------------------------------------------------------------------------- # Roles with assigned permissions # # Each line conforms to the format defined in the # org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc # ----------------------------------------------------------------------------- [roles] # 'admin' role has all permissions, indicated by the wildcard '*' admin = * # The 'schwartz' role can do anything (*) with any lightsaber: schwartz = lightsaber:* # The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with # license plate 'eagle5' (instance specific id) goodguy = winnebago:drive:eagle5
-
入门
核心方法
SecurityUtils.getSubject();//获取当前用户对象 currentUser.getSession();//根据用户获取session currentUser.isAuthenticated();//用户是否被认证 currentUser.getPrincipal();//获取认证 currentUser.hasRole("schwartz");//是否有某个角色 currentUser.isPermitted("lightsaber:wield");//是否有某个权限 currentUser.logout();//注销
public class Quickstart { private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class); public static void main(String[] args) { Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //获取当前用户对象 Subject currentUser = SecurityUtils.getSubject(); //通过当前用户拿到session Session session = currentUser.getSession(); session.setAttribute("someKey", "aValue"); String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { log.info("subject->session [" + value + "]"); } //判断当前用户是否被认证 if (!currentUser.isAuthenticated()) { //token:令牌 UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); //设置记住我 token.setRememberMe(true); try { currentUser.login(token); } catch (UnknownAccountException uae) { log.info("There is no user with username of " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) { log.info("Password for account " + token.getPrincipal() + " was incorrect!"); } catch (LockedAccountException lae) { log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } catch (AuthenticationException ae) { } } log.info("User [" + currentUser.getPrincipal() + "] logged in successfully."); if (currentUser.hasRole("schwartz")) { log.info("May the Schwartz be with you!"); } else { log.info("Hello, mere mortal."); } //粗粒度 if (currentUser.isPermitted("lightsaber:wield")) { log.info("You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); } //细粒度 //a (very powerful) Instance Level permission: if (currentUser.isPermitted("winnebago:drive:eagle5")) { log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } currentUser.logout(); System.exit(0); } }
Springboot整合shiro
依赖
<dependencies>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<!-- shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<!--shiro-thymeleaf整合-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
配置类
-
自定义Realm
需继承AuthorizingRealm,就是授权和认证
public class UserRealm extends AuthorizingRealm { @Resource private UserService userService; //授权 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了=》授权doGetAuthorizationInfo"); //SimpleAuthorizationInfo SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); //获取当前登陆对象 Subject subject = SecurityUtils.getSubject(); //获取user User currentUser = (User) subject.getPrincipal(); if (currentUser.getPerms() != null) { //设置当前用户权限 info.addStringPermission(currentUser.getPerms()); } return info; } //认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("执行了=》认证doGetAuthorizationInfo"); UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken; User user = userService.queryUserByUserName(token.getUsername()); if (user == null) {//没有这个用户 return null;//UnknownAccountException } //登陆成功,user放入session,前台根据是否有此session,动态显示登陆功能 Subject currentSubject = SecurityUtils.getSubject(); Session session = currentSubject.getSession(); session.setAttribute("loginUser",user); //可以加密:MD5: MD5盐值加密:Md5加密过程中添加额外的随机值 //密码认证,shiro做,加密了 return new SimpleAuthenticationInfo(user, user.getPassword(), "");//1.认证2.密码对象3.认证名 } }
-
ShiroConfig
三大核心对象:
- ShiroFilterFactoryBean
- DefaultWebSecurityManager
- Realm
@Configuration public class ShiroConfig { //1.ShiroFilterFactoryBean @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); //设置安全管理器 bean.setSecurityManager(defaultWebSecurityManager); /* anon:无需认证就可访问 authc:必须认证才能访问 user:必须拥有记住我功能才能用 perms:拥有某个资源的权限才能访问 role:拥有某个角色权限才能访问 filterMap.put("/user/add", "authc"); filterMap.put("/user/update", "authc"); filterMap.put("/user/*", "authc");//通配 */ //拦截 Map<String, String> filterMap = new LinkedHashMap<>(); //授权 filterMap.put("/user/add", "perms[user:add]"); filterMap.put("/user/update", "perms[user:update]"); bean.setFilterChainDefinitionMap(filterMap); //设置没有权限会发出的登陆请求 bean.setLoginUrl("/toLogin"); //为授权页面 bean.setUnauthorizedUrl("/noauth"); return bean; } //2.DefaultWebSecurityManager @Bean(name = "securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //关联realm securityManager.setRealm(userRealm); return securityManager; } //3.Realm,需要自定义 @Bean public UserRealm userRealm() { return new UserRealm(); } //整合ShiroDialect,用来整合shiro thymeleaf @Bean public ShiroDialect getShiroDialect() { return new ShiroDialect(); } }
代码
-
controller
@Controller public class MyController { @RequestMapping({"/", "/index"}) public String toIndex(Model model) { model.addAttribute("msg", "hello world"); return "index"; } @RequestMapping("/user/add") public String add() { return "user/add"; } @RequestMapping("/user/update") public String update() { return "user/update"; } @RequestMapping("/toLogin") public String toLogin() { return "login"; } @RequestMapping("/login")//登陆就会调用UserRealm中认证方法 public String login(String username, String password, Model model) { //获取当前用户 Subject subject = SecurityUtils.getSubject(); //封装用户的登陆数据 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //执行登陆方法,如果没有异常就说明OK try { subject.login(token);//登陆成功,返回首页 return "index"; } catch (UnknownAccountException uae) {//用户名不存在 model.addAttribute("msg", "用户名不存在"); return "login"; } catch (IncorrectCredentialsException ice) {//密码错误 model.addAttribute("msg", "密码错误"); return "login"; } } //未授权发出的请求 @RequestMapping("/noauth") @ResponseBody public String unauthorized(){ return "未经授权,不得访问"; } }
-
前端页面
index.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>首页</h1> <!--登陆了的用户不显示登陆连接--> <div th:if="${session.loginUser==null}"> <a th:href="@{/toLogin}">登陆</a> </div> <p th:text="${msg}"></p> <!--只有有user:add的用户才显示增加功能--> <div shiro:hasPermission="user:add"> <a th:href="@{'/user/add'}">增加</a> </div> <!--只有有user:update的用户才显示update功能--> <div shiro:hasPermission="user:update"> <a th:href="@{'/user/update'}">修改</a> </div> </body> </html>
login.html
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登陆</h1> <p th:text="${msg}" style="color: red"></p> <form th:action="@{'/login'}"> <p>用户名:<input type="text" name="username"></p> <p>密码:<input type="text" name="password"></p> <p><input type="submit"></p> </form> </body> </html>
add.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>add</h1> </body> </html>
update.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>update</h1> </body> </html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY