如果你的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就算是搭建完成了,至于其余的高级特性,还需要小伙伴门私下里自行研究了!
如有不明之处,欢迎下方评论指正,感谢您的阅读!
如果你的shiro没学明白,那么应该看看这篇文章,将shiro整合进springboot的更多相关文章
- 没学过CSS等前端的我,也想美化一下自己的博客
随便说几句: 自己一直学的都是 C++和 Java 以及 Python语言,根本不懂高大上的 CSS 和 著名的 HTML5.感觉那些能自己设计那么漂亮的博客的朋友都好厉害.可以自己加上博客公告栏的小 ...
- 为什么学完C语言觉得好像没学一般?
不少同学从Hello world学到文件操作之后,回顾感觉会又不会? 学会了又感觉没学会?这种不踏实.模糊虚无的感觉? 原因在于编程不同于理论学科,你听懂和理解了理论就可以运用. 比如历史地理,看 ...
- 又到期末了,为什么学完C语言觉得好像没学一般?复习资料来一份
不少同学从Hello world学到文件操作之后,回顾感觉会又不会? 学会了又感觉没学会?这种不踏实.模糊虚无的感觉? 原因在于编程不同于理论学科,你听懂和理解了理论就可以运用,比如历史地理,看完书, ...
- 我没学过计算机,是怎么接了四个私活还挣了两个 iPad 的?
你好,我是悟空哥,「7年项目开发经验,全栈工程师,开发组长,超喜欢图解编程底层原理」.我还手写了2个小程序,Java刷题小程序,PMP刷题小程序.我的 GitHub. 前言 大家看到这篇文章的时候,我 ...
- log日志重复输出问题(没弄明白原因)
在别的模块调用定义好的函数 输出的日志出现第一次输出输出一条,第二次输出输出两条...的情况 最后在定义函数处remove了句柄 引用了https://blog.csdn.net/huilan_sam ...
- 一步步教你轻松学支持向量机SVM算法之案例篇2
一步步教你轻松学支持向量机SVM算法之案例篇2 (白宁超 2018年10月22日10:09:07) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...
- 一步步教你轻松学支持向量机SVM算法之理论篇1
一步步教你轻松学支持向量机SVM算法之理论篇1 (白宁超 2018年10月22日10:03:35) 摘要:支持向量机即SVM(Support Vector Machine) ,是一种监督学习算法,属于 ...
- JSP还有必要学吗?这篇文章告诉你
阅读本文大概需要 12.4 分钟. 来源:http://suo.im/4wqRi7 作者:杨明翰 前戏 前后端分离已成为互联网项目开发的业界标准使用方式,通过nginx+tomcat的方式(也可以 ...
- 如果你每次面试前都要去背一篇Spring中Bean的生命周期,请看完这篇文章
前言 当你准备去复习Spring中Bean的生命周期的时候,这个时候你开始上网找资料,很大概率会看到下面这张图: 先不论这张图上是否全面,但是就说这张图吧,你是不是背了又忘,忘了又背? 究其原因在于, ...
随机推荐
- 【bug记录】jpa 解决org.hibernate.lazyinitializationexception could not initialize proxy - no session
前言 最近开发项目比较忙,Spring Cloud的笔记得稍稍放放了,下午出来个bug,恶心的不行,功能很简单,也没有什么级联或复杂的映射关系,就是一直在报三个异常 Caused by: com.fa ...
- BZOJ 1002--[FJOI2007]轮状病毒(高精度)
1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 6858 Solved: 3745[Submit][Statu ...
- 用navicat远程连接mysql:Can't connect to MySQL server (10060)
出现这种现象的原因有两个,一个是当前用户被mysql服务器拒绝,另外一个原因是3306端口被被防火墙禁掉,无法连接到该端口.解决方法如下: 1.设置远程用户访问权限: // 任何远程主机都可以访问数据 ...
- POST 400 (BAD REQUEST)
遇到这种错,1,F12打开控制台,2,点击network,找到发送的请求. 3,点击请求,4,看右侧的 Header Preview Response 应该能找到原因. 就拿刚才来说,找了好几个小时原 ...
- StormUI详解
StormUI由Cluster Summary,topology summary,supervisor summary,Nimbus Configuration四部分组成,如下图所示: Cluster ...
- Spring JdbcTemplate源码阅读报告
写在前面 spring一直以删繁就简为主旨,所以设计出非常流行的bean管理模式,简化了开发中的Bean的管理,少写了很多重复代码.而JdbcTemplate的设计更令人赞叹,轻量级,可做ORM也可如 ...
- iOS下载图片失败
一.具体问题 开发的过程中,发现某个界面部分图片的显示出现了问题只显示占位图片,取出图片的url在浏览器却是能打开的,各种尝试甚至找同行的朋友帮忙在他们项目里展示都会存在问题,最终发现通过第三方框架S ...
- SQL实现数据行列转换
前言: 在日常的工作中,使用数据库查看数据是很经常的事,数据库的数据非常多,如果此时的数据设计是一行行的设计话,就会有多行同一个用户的数据,查看起来比较费劲,如果数据较多时,不方便查看,为了更加方便工 ...
- POJ 1050
#include <stdio.h> #include <string.h> #define mt 101 int main() { int a[mt][mt]; int st ...
- LabelRank非重叠社区发现算法介绍及代码实现(A Stabilized Label Propagation Algorithm for Community Detection in Networks)
最近在研究基于标签传播的社区分类,LabelRank算法基于标签传播和马尔科夫随机游走思路上改装的算法,引用率较高,打算将代码实现,便于加深理解. 这个算法和Label Propagation 算法不 ...