Shiro实操

    技术2022-07-11  143

    目录

     

    简介

    核心组件

    springboot项目整合shiro

    1、创建springboot应用

    2、自定义过滤器

    基础数据部分

    用户认证

    编写认证 和 授权 规则

    认证过滤器规则:

    授权过滤器规则:

    案例

    登陆认证

     登陆授权

    未授权显示

    shiro整合thymeleaf

    几张图片


    简介

    主流的java安全框架,可以不依赖任何容器,可以运行在javase和javaee项目中

    官网:http://shiro.apache.org/

    主要作用是对访问系统用户,进行身份认证,授权,会话管理,加密等常用操作

    为什么用过滤器能实现的功能要用shiro?解决了什么问题?

           业务比较分散的情况下,编写和管理过滤器的逻辑会复杂和繁杂,可维护性极差。需要结构化和工程化的方式,去解决大型项目安全性的问题。

           shiro就是用来解决大型项目的安全管理的系统化框架

    核心组件

    一般会给 角色  赋予 权限 , 给用户 赋予 角色

    1、UserNamePasswordTocken 封装用户的登陆信息,使用用户的登陆信息创建令牌

    2、SecurityManager 负责安全认证 和 授权

    3、Subject ,抽象了一个用户信息概念

    4、Realm, 开发者自定义模块,根据项目需求 , 验证和授权实现在这里边

    5、AuthenticationInfo 用户角色信息集合,支持认证时使用

    6、AuthorzationInfo,用户角色的权限信息, 授权时使用

    7、DefaultWebSecurityManager, 安全管理器,开发者自定义的Realm,需要注入到管理器中,进行管理才能生效

    8、ShiroFilterFactoryBean, 过滤器工程,底层还是基于过滤器实现,开发者制定规则,shiro执行规则,具体的执行操作交给shiroFilterFactoryBean创建的Filter对象来完成

     

    springboot项目整合shiro

    1、创建springboot应用

    <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.zl</groupId> <artifactId>boot02-shiro</artifactId> <version>0.0.1-SNAPSHOT</version> <name>boot02-shiro</name> <description>Demo project for Spring Boot</description> <properties> <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> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.5.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

     

    2、自定义过滤器

    基础数据部分

    spring: datasource: name: springbootshiro url: jdbc:mysql://localhost:3306/springbootshiro?useUnicode=true&characterEncoding=UTF-8 username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl @Data public class Accounter { private Integer id; private String username; private String password; private String perms; private String role; } @Repository public interface AccounterMapper extends BaseMapper<Accounter> { } @Service public class AccountServiceImpl implements AccountService { @Autowired private AccounterMapper accounterMapper; @Override public Accounter findByUserName(String userName) { QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("username", userName); return accounterMapper.selectOne(queryWrapper); } }

    用户认证

    实现部分

    public class AccountRealm extends AuthorizingRealm { @Autowired private AccountService accountService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null; } /** * 认证 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken; Accounter account = accountService.findByUserName(usernamePasswordToken.getUsername()); if(account != null) { //密码验证 return new SimpleAuthenticationInfo(account, account.getPassword(), getName()); } return null; } }

    配置类部分,串通了shiro的路线

    @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); return shiroFilterFactoryBean; } /** * @Qualifier("accountRealm") 通过名字,从ioc容器里边拿到realm * @param accountRealm * @return */ @Bean public DefaultWebSecurityManager mysecurityManager(@Qualifier("accountRealm") AccountRealm accountRealm) { DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager(); defaultWebSecurityManager.setRealm(accountRealm); return defaultWebSecurityManager; } @Bean public AccountRealm accountRealm() { return new AccountRealm(); } }

    编写认证 和 授权 规则

    认证过滤器规则:

    anon 无须认证  、

    authc 必须认证、 

    authcBase 需要通过HTTPBasic协议认证、

    user 不一定通过认证,只要曾经被shiro记住了

     

    授权过滤器规则:

    perms 必须拥有某个权限才能访问

    role 必须拥有某个角色才能访问

    port 请求的端口必须为指定的值

    rest 请求必须基于 Restful  post、put、get、delete、

    ssl 必须是安全的url请求,协议必须是https

     

    案例

    1、必须登陆才能访问main.html

    2、当前用户必须拥有mananger授权才能访问manager.html

    3、当前用户必须拥有administator这个角色才能访问administator.html

    登陆认证

    @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //集合设置 Map<String,String> sourceMap = new HashMap<>(); shiroFilterFactoryBean.setLoginUrl("/login"); return shiroFilterFactoryBean; } @Controller public class AccountController { @GetMapping("/{url}") public String redirect(@PathVariable("url") String url) { return url; } @PostMapping("/login") public String login(String username, String password, Model model) { Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); try { subject.login(usernamePasswordToken); Account account = (Account)subject.getPrincipal(); subject.getSession().setAttribute("account",account); return "index"; }catch (UnknownAccountException e) { //用户不存在异常 model.addAttribute("msg","用户名错误" ); return "login"; }catch (IncorrectCredentialsException ie) { //非法密码异常 model.addAttribute("msg","密码错误" ); return "login"; } } } login.html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="shortcut icon" href="#"/> </head> <body> <form action="/login" method="post"> <table> <span th:text="${msg}" style="color: red"></span> <tr> <td>用户名:</td> <td> <input type="text" name="username" /> </td> </tr> <tr> <td>密码:</td> <td> <input type="password" name="password" /> </td> </tr> <tr> <td> <input type="submit" value="登陆" /> </td> </tr> </table> </form> </body> </html> index.html <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" > <head> <meta charset="UTF-8"> <title>Title</title> <link rel="shortcut icon" href="#"/> </head> <body> <h1>index</h1> <div th:if="${session.account != null}"> <span th:text="${session.account.username}+'欢迎回来!'"></span><a href="/logout">退出</a> </div> <a href="/main">main</a> <br/> <a href="manage">manage</a> <br/> <a href="/administrator">administrator</a> </body> </html>

     登陆授权

    @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //集合设置 Map<String,String> sourceMap = new HashMap<>(); sourceMap.put("/main", "authc"); sourceMap.put("/manage", "perms[manage]"); sourceMap.put("/administrator", "roles[administrator]"); shiroFilterFactoryBean.setFilterChainDefinitionMap(sourceMap); shiroFilterFactoryBean.setLoginUrl("/login"); return shiroFilterFactoryBean; } @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { Subject subject = SecurityUtils.getSubject(); Account account = (Account)subject.getPrincipal(); //设置角色 Set<String> setRole = new HashSet<>(); setRole.add(account.getRole()); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setRoles(setRole); // 设置权限 info.addStringPermission(account.getPerms()); return info; }

    未授权显示

    @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean (@Qualifier("mysecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager); //集合设置 Map<String,String> sourceMap = new HashMap<>(); sourceMap.put("/main", "authc"); sourceMap.put("/manage", "perms[manage]"); sourceMap.put("/administrator", "roles[administrator]"); shiroFilterFactoryBean.setFilterChainDefinitionMap(sourceMap); shiroFilterFactoryBean.setLoginUrl("/login"); //设置未授权页面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauth"); return shiroFilterFactoryBean; } @GetMapping("/unauth") @ResponseBody public String unauth(){ return "未授权,无法访问!"; }

    shiro整合thymeleaf

    1、依赖

    <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.0.0</version> </dependency>

    2、配置类加入 方言识别

    @Bean public ShiroDialect shiroDialect(){ return new ShiroDialect(); }

    3、html 命名空间

    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> <link rel="shortcut icon" href="#"/> </head> <body> <h1>index</h1> <div th:if="${session.account != null}"> <span th:text="${session.account.username}+'欢迎回来!'"></span><a href="/logout">退出</a> </div> <a href="/main">main</a> <br/> <div shiro:hasPermission="manage"> <a href="manage">manage</a> <br/> </div> <div shiro:hasRole="administrator"> <a href="/administrator">administrator</a> </div> </body> </html>

     

    几张图片

     

    Processed: 0.010, SQL: 9