如果你的shiro没学明白,那么应该看看这篇文章,将shiro整合进springboot

最近在做项目的时候需要用到shiro做认证和授权来管理资源

在网上看了很多文章,发现大多数都是把官方文档的简介摘抄一段,然后就开始贴代码,告诉你怎么怎么做,怎么怎么做

相信很多小伙伴即使是跟着那些示例代码做完配完,并且成功搭建,估计也是一头雾水,可能会不理解,为什么要这么做

本人也是在看了大量文章之后,然后又自己动手搭了一便,得出如下使用的感悟,特此分享给大家

依照程序,我要在这里对shiro做一些简介,以下内容翻译与官网首页

Apache SHIO是一个功能强大、易于使用的Java安全框架,它执行身份验证、授权、加密和会话管理。有了Shiro易于理解的API,您可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的Web和企业应用程序。

其次要和相关类似技术进行一个对比

在spring大家族中,安全框架也是肯定有的,那就是spring-security,至于我们为什么要用shiro而不用spring-security大家可以自行搜索下相关内容我们在此就不过多阐述了

ok,废话少说,我们直奔主题

可能有些小伙伴在用shiro这种框架的时候会有这种疑惑,我们为什么要用这样的框架

首先我们开发者在做一个项目的时候,对资源的权限控制和划分应该是必不可少的一部分,即哪些资源哪些角色可以访问,哪些资源哪些角色不可以访问

那么试想下这种情况,如果没有shiro这种框架,你要实现对资源的权限控制,可能会有如下几点

1,首先你要设计角色

2,为资源分配角色,并且统一注册进配置文件中

4,给用户授权

3,每当有新的请求进来时你要验证当前用户的身份,然后遍历资源权限的配置文件,查明当前用户的角色是否有资格访问

第1,2步体现在设计层面,第3步要周而复始每当有新的请求的时候都要做一遍的事情,这一步可以使用spring提供的aop机制,配置成前置通知

综上所述是不是感觉很麻烦

那么shiro呢,就为我们简化了上述步骤,使我们能以一种较为简洁的方式,实现对项目资源的权限控制

同时shiro还集成了很多加密机制(MD5,base64,SHA)等,可以直接以调用的方式对我们的密码或者报文进行加密措施非常的方便

首先我门引入pom依赖

<!--  shiro --><dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-spring</artifactId>    <version>1.3.2</version></dependency>

集成shiro非常的简单,我门只需要自定义一下我们的认证和授权然后配置以下过滤器即可

认证和授权

import com.sc.starry_sky.entity.PageData;
import com.sc.starry_sky.service.UserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;

@Component("MyShiroRealm")
public class MyShiroRealm extends AuthorizingRealm{

    //用于用户查询
    @Autowired
    private UserService userService;

    //添加角色权限
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取用户
        PageData user = (PageData) principalCollection.getPrimaryPrincipal();
        //获取权限列表
        ArrayList<PageData> roles = (ArrayList<PageData>) user.get("roles");
        //添加角色和权限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        roles.forEach(item -> simpleAuthorizationInfo.addRole(item.getString("roleName")));
        return simpleAuthorizationInfo;
    }

    //登录认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;

        String username = usernamePasswordToken.getUsername();

        PageData user = userService.findUserByUsername(username);
        if (user == null) {
            return null;
        } else {
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user, user.getString("password"), getName());
            return simpleAuthenticationInfo;
        }
    }

}

自定义密码的校验规则

import com.sc.starry_sky.util.PasswordUtil;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import com.sc.starry_sky.entity.PageData;
import org.springframework.stereotype.Component;

@Component("CredentialMatcher")
public class CredentialMatcher extends SimpleCredentialsMatcher{

    @Autowired
    PasswordUtil passwordUtil;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        PageData user = (PageData)info.getPrincipals().getPrimaryPrincipal(); //这里取出的是我们在认证方法中放入的用户信息也就是我们从数据库查询出的用户信息
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;//这里是前端发送的用户名密码信息
        String requestPwd = new String(usernamePasswordToken.getPassword());
        String requestPwdEncryption = passwordUtil.getEncryptionPassword(requestPwd, user.getString("userId"));//获取加密后的密码

        String dbPwd = user.getString("password");
        return requestPwdEncryption.equals(dbPwd);
    }

}

密码加密工具类

import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Random;

@Component
public class PasswordUtil {

    @Value("${password.algorithmName}") //这个可以在application.properites里自行配置 如(md5,sha,base64)等等
    private String algorithmName;
    @Value("${password.hashIterations}")//这个是加密的次数
    private int hashIterations;

    /**
     * 返回加密后的密码
     * @param password
     * @param userId
     * @return
     */
    public String getEncryptionPassword(String password , String userId){      //四个参数的讲解 1,加密类型,2,原始密码,3,盐值,可以是固定的,这里我门采用用户的userId作为用户的盐值进行加盐,4,加密的迭代次数
        return new SimpleHash(algorithmName, password, userId, hashIterations).toString();
    }}

配置过滤器

import java.util.HashMap;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {

    @Autowired
    MyShiroRealm myShiroRealm;
    @Autowired
    CredentialMatcher CredentialMatcher;

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(securityManager);

        filterFactoryBean.setLoginUrl("/loginPage");

        // 成功登陆后的界面
        //filterFactoryBean.setSuccessUrl("/indexPage");

        // 没有权限访问的界面
        //filterFactoryBean.setUnauthorizedUrl("/unauthorized");

        HashMap<String, String> filterMap = new HashMap<>();

        // 配置不会被拦截的链接 顺序判断
        filterMap.put("/static/**", "anon");
        filterMap.put("/doLogin", "anon");
        filterMap.put("/loginPage", "anon");
        filterMap.put("/SubmitRegistInformation", "anon");
        filterMap.put("/SendMessageCode", "anon");
        // 配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterMap.put("/logout", "logout");

        // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterMap.put("/**", "authc");
        // 所有的页面都需要user这个角色
        filterMap.put("/**", "roles[user]");

        filterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return filterFactoryBean;
    }

    @Bean("securityManager")
    public SecurityManager securityManager(@Qualifier("myShiroRealm") MyShiroRealm authRealm) {
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(authRealm);
        return manager;
    }

    @Bean("myShiroRealm")
    public MyShiroRealm myShiroRealm() {
        //设置缓存
        myShiroRealm.setCacheManager(new MemoryConstrainedCacheManager());
        //设置密码校验规则
        myShiroRealm.setCredentialsMatcher(CredentialMatcher);
        return myShiroRealm;
    }

}

登录的controller方法

@Controller
public class LoginRegistController extends BaseController {

    @Autowired
    PasswordUtil passwordUtil;

    @Autowired
    UserService userService;

    @PostMapping("/doLogin")
    @ResponseBody
    public Map<String,Object> doLogin(){
        HashMap<String, Object> resultMap = new HashMap<String, Object>();
        try{
            PageData user = this.getPageData();
            UsernamePasswordToken token = new UsernamePasswordToken(user.getString("username"), user.getString("password"));
            SecurityUtils.getSubject().login(token);
            PageData db_user = (PageData) SecurityUtils.getSubject().getPrincipal();//登录成功之后,取出用户信息放进session存储域
            this.getRequest().getSession().setAttribute("user_information",db_user);
            resultMap.put("status", 200);
            resultMap.put("message", "登录成功");
            return resultMap;
        }catch(Exception e){
            resultMap.put("status", 500);
            resultMap.put("message", e.getMessage());
            return resultMap;
        }
    }

    @GetMapping("/loginPage")
    public ModelAndView loginPage(String name){
        ModelAndView mv = new ModelAndView();
        mv.setViewName("login_regist");
        return mv;
    }}

这样一个基础的shiro就算是搭建完成了,至于其余的高级特性,还需要小伙伴门私下里自行研究了!

如有不明之处,欢迎下方评论指正,感谢您的阅读!

原文地址:https://www.cnblogs.com/monkSand/p/10353900.html

时间: 2024-08-28 23:51:08

如果你的shiro没学明白,那么应该看看这篇文章,将shiro整合进springboot的相关文章

引用传递分析/没学明白(不用太纠结垃圾内存的问题

类本身属于引用数据类型,既然是引用数据类型,那么牵扯到内存的引用传递,引用传递的本质:同一块堆内存空间可以 被不同的栈内存所指向,所有的引用传递的本质是一场堆内存的游戏 引用内存的过程中会产生垃圾,对垃圾的产生进行分析:所有没有栈内存指向的堆内存空间,就叫垃圾空间 所有的垃圾将被GC(Garbage Collector,垃圾收集器)不定期进行回收,并且释放空间,如果垃圾过多,一定 影响GC的处理性能,从而影响程序的运行速度. 一个栈内存只能保存一个堆内存的地址数据,如果发生更改,则之前地址数据将

如果你朋友不知道什么是云计算,请把这篇文章转给TA

云计算这个概念从提出到今天,已经差不多10年了.在这10年间,云计算取得了飞速的发展与翻天覆地的变化."云"从一个听起来离我们特别遥远的概念,到现如今家喻户晓,这是所有从事云计算工作者共同努力的结果.云计算正带给各行各业带来哪些颠覆性改变呢?跟随小编一起来看看: 云计算改变物流行业: 早几年我们双十一网上购物的时候,常常在下单后要等待很久才能收到快递,平时2.3天就能收到的包裹,在双十一期间,由于包裹太多物流繁忙,常常需要眼巴巴等待8.9天才能拿到快递.但是近两年有个很明显的感受,即便

程序员的奋斗史(四十六)——大学断代史(十)——给学弟学妹们的忠告——终结篇

文/温国兵 「写在前面」 大学断代史终于要完结了,就像一条再长的路总有终点一样.该系列文章前前后后写了一两个月,也该收尾了,至于收尾的文章,想了想,决定写写自己对学弟学妹的忠告.本篇文章以话题的形式呈现. 「关于专业」 我相信大多数的读者在高考填志愿都不知道软件工程或者计算机专业是做啥的,稀里糊涂就踏上了这条IT不归路.身处小乡村,消息相对闭塞,能使用电脑都是奢侈的事情,这就是当初我高考后的境况,相信现在有很大的改变.如果你对IT行业抱有一番热情,恭喜你,选对了好专业,好好学,今后的路错不了.如

50个查询系列-第五个查询:查询没学过“叶平”老师课的同学的学号、姓名;

查询没学过"叶平"老师课的同学的学号.姓名: 我们反着来 !不是要查没上过课的同学的名字吗.我们先查上叶平的课的学生. 思路: 1.先去查叶平上的课的课程id: SELECT t1.courseid kid FROM tblcourse t1, (SELECT tblteacher.TeaId tid FROM tblteacher WHERE tblteacher.TeaName='叶平') t2 WHERE t1.teaid=t2.tid -- 查出来叶平老师上的课的课程id 结果

情人节了,可怜的IT运维男,没学过ITIL,还是没有女朋友……

2015年情人节来临,亲爱的IT男,别告诉我,你还没有女朋友,你为什么总在加班,没时间恋爱:为什么总在被业务部门抱怨,没心情恋爱:为什么工作总也做不顺,没信心恋爱!!!为什么这个可怜的人是你,原因很简单,你还没学ITIL吧. 你是一个企业的IT运维人员吗?你们的IT运维工作是否杂而无章,是否责任不明?你是否对复杂的运维流程和客户的无尽抱怨束手无策?你是否希望在领导面前提出有效的合理建议,以提升企业的IT服务管理水平?ITIL就是您的解决方案. 对于企业实施ITIL,可以有助于最终进行完善的服务管

“玩游戏,我没学到东西”,一定是坏消息?

"玩游戏,没学到任何东西",当这句话出现的时候,似乎很容易让人立刻联想起玩物丧志.当时我在一则新闻中看到此句时,心里更是一沉. 文/张书乐(TMT行业观察者.游戏产业时评人,人民网.人民邮电报专栏作者) 刊载于<人民邮电报>2017年4月7日<乐游记>专栏138期 因为这则新闻是讲述国外一个教育游戏团队的创业历程的.可不是糟糕了吗!可把整个句子一看,乐了."一开始,他们让一班10岁孩子试玩了<宇宙大爆炸传说>.一个女孩反映她在玩游戏的过程中

没学过CSS等前端的我,也想美化一下自己的博客

随便说几句: 自己一直学的都是 C++和 Java 以及 Python语言,根本不懂高大上的 CSS 和 著名的 HTML5.感觉那些能自己设计那么漂亮的博客的朋友都好厉害.可以自己加上博客公告栏的小宠物和微博以及加上背景音乐,都感觉好牛逼,好高大上,博客的亲切感立马就上来了. 可是我又没学过 CSS等前端的东西,心想,搞这么漂亮的博客会不会很难啊?那些</class>这些什么鬼?会不会很繁琐?难道要我把 前端的东西学习一边才行? 开始: 然而并非如此,我不会前端,可是我也可以弄:小宠物和微博

没搞明白fileinput模块的inplace!

__author__ = 'sophi' import fileinput product_list = [] f = open("porduct.txt","r",encoding="utf-8") #打开文件 for line in f.readlines(): line = line.strip() index,item = line.split(":") #冒号分割 product_list.append((index

学计算机的值得一看的文章,跟帖也很有水平啊

转自http://blog.csdn.net/Xviewee/article/details/1606247 回复CSDN和KAOYAN诸位网友的几点看法,(为避免吵架,郑重声明,本人不是高手,只是有感而发的一点个人陋见,欢迎指正,事先感谢): 就我自己的理解,谈谈我对读研和软件学院的看法,不妥之处一笑了之即可. 如果你有实际开发工作经验,感觉自己的水平和实力进入了一个高原期,迫切需要从理论上提高,那么计算机学院是唯一选择.因为计算机学院才能让你在理论上更上一层楼.软件学院从教学计划上就没有