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>
View Code

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);
    }
}
View Code

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
View Code

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
View Code

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>
View Code

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();
    }
}
View Code

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();
//    }

    }
View Code

 

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>
View Code

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
View Code

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>
View Code

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>
View Code

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";
        }

    }
View Code

 

posted @ 2022-05-04 20:30  磕伴  阅读(177)  评论(0)    收藏  举报