Shiro
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
目录
1简单实现Shiro
2.整合springboot
3.整合mybatis
4.整合thymeleaf
1.简单实现Shiro
1.1 相关依赖
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
1.2 Quickstart.java
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.realm.text.IniRealm; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple Quickstart application showing how to use Shiro's API. * * @since 0.9 RC2 */ public class Quickstart { private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class); public static void main(String[] args) { DefaultSecurityManager securityManager = new DefaultSecurityManager(); IniRealm iniRealm = new IniRealm("classpath:shiro.ini"); securityManager.setRealm(iniRealm); SecurityUtils.setSecurityManager(securityManager); // Now that a simple Shiro environment is set up, let's see what you can do: // get the currently executing user: Subject currentUser = SecurityUtils.getSubject(); //获取当前用户 // Do some stuff with a Session (no need for a web or EJB container!!!) Session session = currentUser.getSession(); //通过当前用户拿到session session.setAttribute("someKey", "aValue"); //如何用seession 存取值 String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { log.info("Retrieved the correct value! [" + value + "]"); } // let's login the current user so we can check against roles and permissions: if (!currentUser.isAuthenticated()) { //判断当前用户是否被认证 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 more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) { //unexpected condition? error? } } //say who they are: //print their identifying principal (in this case, a username): log.info("User [" + currentUser.getPrincipal() + "] logged in successfully."); //test a role: if (currentUser.hasRole("schwartz")) { log.info("May the Schwartz be with you!"); } else { log.info("Hello, mere mortal."); } //test a typed permission (not instance-level) 粗粒度 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!"); } //all done - log out! 注销 currentUser.logout(); System.exit(0); } }
1.3 log4j.properties
log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n # General Apache libraries log4j.logger.org.apache=WARN # Spring log4j.logger.org.springframework=WARN # Default Shiro logging log4j.logger.org.apache.shiro=INFO # Disable verbose logging log4j.logger.org.apache.shiro.util.ThreadContext=WARN log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
1.4 shiro.ini
[users] root = secret, admin guest = guest, guest presidentskroob = 12345, president darkhelmet = ludicrousspeed, darklord, schwartz lonestarr = vespa, goodguy, schwartz [roles] admin = * schwartz = lightsaber:* goodguy = winnebago:drive:eagle5
2.整合springboot
2.1.导入相关依赖
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.9.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.9.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.9.0</version> </dependency>
2.2.编写Shiro 配置类
@Controller public class ShiroConfig { // shiroFilterFactoryBean @Bean(name = "shiroFilterFactoryBean") public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){ //设置安全管理器 ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(defaultWebSecurityManager); //添加shiro的内置过滤器 /* 添加Shiro内置过滤器,常用的有如下过滤器: anon: 无需认证就可以访问 authc: 必须认证才可以访问 user: 如果使用了记住我功能就可以直接访问 perms: 拥有某个资源权限才可以访问 role: 拥有某个角色权限才可以访问` */ Map<String,String> filtermap = new LinkedHashMap<>(); filtermap.put("/add","perms[user:add]"); //用户有add这个权限才可以访问 // filtermap.put("/update","role[A]");//设置权限 ,权限不够的会跳到登录界面 filtermap.put("/update","authc");//设置权限 ,权限不够的会跳到登录界面 // filtermap.put("/user/*","authc"); //支持通配符 bean.setFilterChainDefinitionMap(filtermap); //设置未授权页面界面 // bean.setUnauthorizedUrl("/*"); //设置登录界面 bean.setLoginUrl("/tologin"); return bean; } // DafaultWebSecurityManager @Bean // 指定名 方法名就是~ public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userReal") UserRealm userRealm){ DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); //关联userRealm defaultWebSecurityManager.setRealm(userRealm); return defaultWebSecurityManager; } // 创建realm对象,需要自定义类 @Bean(name = "userReal") //自己写的类被spring托管 public UserRealm userRealm(){ return new UserRealm(); } //整合shiro 和thynmeleaf @Bean(name = "shiroDialect" ) public ShiroDialect getShiroDialect(){ return new ShiroDialect(); } }
2.3.自定义一个 realm 的类,用来编写一些查询的方法,或者认证与授权的逻辑
<验证用户账号密码和 赋予一定的权限(供前端判断),>
//自定义UserRealm public class UserRealm extends AuthorizingRealm { @Autowired private UserServiceImpl userService; //ctrl+i ctrl+i:实现接口中的方法 @Override //授权 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("=====>执行了授权---AuthorizationInfo"); SimpleAuthorizationInfo info1 = new SimpleAuthorizationInfo(); Subject subject = SecurityUtils.getSubject(); User currentUser = (User)subject.getPrincipal(); //拿到user对象 if(currentUser.getId()>5){ info1.addStringPermission("user_add"); // info1.addRole("A"); } return info1; } @Override//认证 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("=====>执行了认证---AuthenticationInfo"); //点了登录(用户名密码)就会做这个认证 UsernamePasswordToken usertoken= (UsernamePasswordToken)authenticationToken; //UsernamePasswordToken 有联系的,会接收到相关的信息 User user=userService.queryUserByname(usertoken.getUsername()); if(user==null){ return null; //抛出异常 用户名不存在异常 } System.out.println(getType(user.getAge())); // Integer.toString(i); //密码认证,Shiro来做 //密码可以加密 md5盐值加密 ByteSource bytes = ByteSource.Util.bytes(user.getName()); System.out.println(bytes); //(需要传递的资源,密码,加密,) return new SimpleAuthenticationInfo(user,Integer.toString(user.getAge()),bytes,""); } //对象的属性是int 从数据库查出来的时候是string public static String getType(Object obj) { return obj.getClass().toString(); } // public static String getType(Object obj) { // return obj.getClass().toString(); // } }
3.整合mybatis
3.1.导入相关依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.9</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
3.2 配置
application.properties mybatis.type-aliases-package=com.ljm.pojo mybatis.mapper-locations=classpath:mybatis/mapper/*.xml application.yml spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource #指定数据源 # jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入 #如果允许时报错 java.lang.ClassNotFoundException:org.apache.log4j.Priority #则导入 log4j 依赖即可,Maven 地址:https: //mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
3.3 pojo mapper service
3.4调用
4.整合thymeleaf
4.1导入相关依赖
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
4.2 命名空间
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
4.3相关表达
<!-- 权限有user_add这个的就展示标签内的内容--> <div shiro:hasPermission="user_add"> <a th:href="@{/add}">add</a> <hr/> </div> <!-- 没有权限就显示,这两种都行--> <!-- <div shiro:notAuthenticated>--> <div shiro:guest="true"> <a th:href="@{/tologin}">登录</a> </div> <!-- 利用session传值--> <div th:if="${session.a != null}"> <a th:text="${session.a}"></a> </div>
4.4 配合session model传递值 异常捕获与传递
public String login(String username,String password,Model model){ //获取当前的用户 Subject subject = SecurityUtils.getSubject(); //封装用户的操作数据 UsernamePasswordToken token = new UsernamePasswordToken(username, password); //执行登录方法,没有异常就ok try { subject.login(token); //执行了登录操作 //给前端传值可以用Session Session session = subject.getSession(); session.setAttribute("a",123); return "index"; } catch (UnknownAccountException uae) { model.addAttribute("msg","用户名错误"); return "login"; } catch (IncorrectCredentialsException ice) { model.addAttribute("msg","密码错误"); return "login"; } catch (LockedAccountException lae) { model.addAttribute("msg","用户被锁定,请联系管理员"); return "login"; } // ... catch more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) { model.addAttribute("msg","error"); return "login"; } }

浙公网安备 33010602011771号