0
点赞
收藏
分享

微信扫一扫

Shiro快速上手

四月天2021 2022-04-14 阅读 47

1. Shiro简介

1.1 什么是Shiro

  • Apache Shiro是一个Java的安全(权限)框架。
  • Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。
  • Shiro可以完成,认证,授权,加密,会话管理,Web集成,缓存等。
  • 下载地址: http://shiro.apache.org/

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gyDGWx5N-1649891528381)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220412212652361.png)]

1.2 有哪些功能?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NhzxWhRG-1649891528382)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220412212746792.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gFgTIaAL-1649891528383)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220412212817756.png)]

1.3 Shiro架构 (外部)

从外部来看Shiro,即从应用程序角度来观察如何使用shiro完成工作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wFDwtk2U-1649891528383)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220412212858779.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-naAmPTUc-1649891528384)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220412212944825.png)]

1.4 Shiro架构 (内部)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7O7H6ykI-1649891528385)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220412213017295.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hhYytjKG-1649891528385)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220412213051077.png)]

2. Hello World

2.1 快速实战

查看官网文档: http://shiro.apache.org/tutorial.html
官方的quickstart: https://github.com/apache/shiro/tree/master/samples/quickstart/

在这里插入图片描述

在这里插入图片描述

在Spring Boot整合shiro中,启动程序出现了下面的错误:

***************************

APPLICATION FAILED TO START

***************************

Description:

Method filterShiroFilterRegistrationBean in org.apache.shiro.spring.config.web.autoconfigure.ShiroWebFilterConfiguration required a bean named 'shiroFilterFactoryBean' that could not be found.


Action:

Consider defining a bean named 'shiroFilterFactoryBean' in your configuration.

原因: 未指定bean的名称,默认采用的是 “方法名” + "首字母小写"的配置方式

解决方法:

  1. 在生产shiroFilterFactoryBean的方法上指定Bean名称
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean xxx(SecurityManager securityManager) {
	...
}
  1. 在生产shiroFilterFactoryBean的方法上修改方法名字为shiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
	...
}

3.简单的shiro-springboot项目

配置文件

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource


    #Spring Boot默认是不注入这些属性值的,需要自己绑定
    #druid数据源专有配置
    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,wa11,1og4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.s1owSqlMi1lis=500
mybatis.type-aliases-package=com.xz.pojo
mybatis.mapper-locations=classpath:mapper/*.xml

项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SX8Sk2C5-1649891528387)(C:\Users\许正\AppData\Roaming\Typora\typora-user-images\image-20220414070927759.png)]

核心代码

UserRealm.java

package com.xz.controller;

import com.xz.pojo.User;
import com.xz.service.UserService;
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.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author 许正
 * @version 1.0
 */

//自定义的 UserRealm:  extends AuthorizingRealm 即可
public class UserRealm extends AuthorizingRealm {

    @Autowired
    UserService userService;


    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("执行了 ==> 授权doGetAuthorizationInfo");
        //AuthorizationInfo
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addStringPermission("user:add");

        //拿到当前登陆的这个对象
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User) subject.getPrincipal();//拿到User对象

        //设置当前用户的权限
        info.addStringPermission(currentUser.getPerms());

        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("执行了 ==> 认证doGetAuthenticationInfo");
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        //连接数据库
        User user = userService.queryUserByName(usernamePasswordToken.getUsername());

        if (user == null) {
            return null;//UnknownAccountException
        }

        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("loginUser", user);

        //密码认证, shiro做(加密)
        //可以加密: MD5(例: 123456): e10adc3949ba59abbe56e057f20f883e MD5盐值加密: e10adc3949ba59abbe56e057f2ef883e + username
        return new SimpleAuthenticationInfo(user, user.getPwd(), "");
    }
}

MyController.java

package com.xz.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author 许正
 * @version 1.0
 */
@Controller
public class MyController {

    @RequestMapping({"/", "/index", "/index.html"})
    public String toIndex(Model model) {

        model.addAttribute("msg", "Hello, Shiro!");

        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")
    public String login(String username, String password, Model model) {
        //获取当前的用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登陆数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try {
            subject.login(token);//执行登录方法, 如果没有异常就OK
            return "index";
        } catch (UnknownAccountException e) {//用户名不存在
            model.addAttribute("msg", "用户名不存在!");
            return "login";
        } catch (IncorrectCredentialsException e) {//密码不存在
            model.addAttribute("msg", "密码不存在!");
            return "login";
        }

    }

    @RequestMapping("/noauth")
    @ResponseBody
    public String unauthorized() {
        return "未经授权无法访问此页面";
    }
}

ShiroConfig.java

package com.xz.shiroconfig;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.xz.controller.UserRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author 许正
 * @version 1.0
 */

@Configuration
public class ShiroConfig {

    //3. ShiroFilterFactoryBean
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();

        //关联DefaultWebSecurityManager, 设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);

        //添加shiro的内置过滤器
        /*
            anon: 无需认证就可以访问
            authc: 必须认证了才能让问
            user: 必须拥有记住我功能才能用
            perms: 拥有对某个资源的权限才能访问;
            role: 拥有某个角色权限才能访问
            //        filterMap.put("/user/add", "anon");
            //        filterMap.put("/user/update", "authc");
        */
        //拦截
        Map<String, String> filterMap = new LinkedHashMap<>();

        //授权,正常的情况下, 没有授权会跳转到未授权页面
        filterMap.put("/user/add", "perms[user:add]");
        filterMap.put("/user/update", "perms[user:update]");

        filterMap.put("/user/*", "authc");
        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();

        //关联UserRealm
        securityManager.setRealm(userRealm);

        return securityManager;
    }

    //1. 创建realm对象, 需要自定义类
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

    //整合ShiroDialect:用来整合shiro-thymeleaf
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }


}

需要该项目的小伙伴可以私信向我要哦~~
一起加油!!!

举报

相关推荐

0 条评论