springboot2.x整合shiro权限框架的使用
序
在实际项目中,经常需要用到角色权限区分,以此来为不同的角色赋予不同的权利,分配不同的任务。比如,普通用户只能浏览;会员可以浏览和评论;超级会员可以浏览、评论和看视频课等;实际应用场景很多。毫不夸张的说,几乎每个完整的项目都会设计到权限管理。
在SpringBoot中做权限管理,一般来说,主流的方案是SpringSecurity,但是由于SpringSecurity过于庞大和复杂,只要能满足业务需要,大多数公司还是会选择ApacheShiro来使用。
一般来说,SpringSecurity和Shiro的区别如下:
| SpringSecurity | ApacheShiro |
|---|---|
| 重量级的安全管理框架 | 轻量级的安全管理框架 |
| 概念复杂,配置繁琐 | 概念简单、配置简单 |
| 功能强大 | 功能简单 |
因此,这篇文章,阿淼首先会带大家了解ApacheShiro,然后和大家一起将shiro权限框架整合到SpringBoot中,以达到快速的实现整合权限管理的功能。
走进ApacheShiro
官网认知
照例又去官网扒了扒介绍:
ApacheShiro™isapowerfulandeasy-to-useJavasecurityframeworkthatperformsauthentication,authorization,cryptography,andsessionmanagement.WithShiro'seasy-to-understandAPI,youcanquicklyandeasilysecureanyapplication–fromthesmallestmobileapplicationstothelargestwebandenterpriseapplications.
ApacheShiro™是一个强大且易用的Java安全框架,能够用于身份验证、授权、加密和会话管理。Shiro拥有易于理解的API,您可以快速、轻松地获得任何应用程序——从最小的移动应用程序到最大的网络和企业应用程序。
简而言之,ApacheShiro是一个强大灵活的开源安全框架,可以完全处理身份验证、授权、加密和会话管理。
Shiro能到底能做些什么呢?
- 验证用户身份
- 用户访问权限控制,比如:1、判断用户是否分配了一定的安全角色。2、判断用户是否被授予完成某个操作的权限
- 在非Web或EJB容器的环境下可以任意使用SessionAPI
- 可以响应认证、访问控制,或者Session生命周期中发生的事件
- 可将一个或以上用户安全数据源数据组合成一个复合的用户“view”(视图)
- 支持单点登录(SSO)功能
- 支持提供“RememberMe”服务,获取用户关联信息而无需登录
- ···
为什么今天还要使用ApacheShiro?
对此,官方给出了详细的解释:http://shiro.apache.org/
自2003年以来,框架环境发生了很大变化,因此今天仍然有充分的理由使用Shiro。实际上有很多原因。ApacheShiro是:
- 易于使用-易于使用是该项目的最终目标。应用程序安全性可能非常令人困惑和沮丧,并被视为“必要的邪恶”。如果您使它易于使用,以使新手程序员可以开始使用它,那么就不必再痛苦了。
- 全面-ApacheShiro声称没有其他具有范围广度的安全框架,因此它可能是满足安全需求的“一站式服务”。
- 灵活-ApacheShiro可以在任何应用程序环境中工作。尽管它可以在Web,EJB和IoC环境中运行,但并不需要它们。Shiro也不要求任何规范,甚至没有很多依赖性。
- 具有Web功能-ApacheShiro具有出色的Web应用程序支持,使您可以基于应用程序URL和Web协议(例如REST)创建灵活的安全策略,同时还提供一组JSP库来控制页面输出。
- 可插拔-Shiro干净的API和设计模式使它易于与许多其他框架和应用程序集成。您会看到Shiro与Spring,Grails,Wicket,Tapestry,Mule,ApacheCamel,Vaadin等框架无缝集成。
- 受支持-ApacheShiro是ApacheSoftwareFoundation(Apache软件基金会)的一部分,该组织被证明以其社区的最大利益行事。项目开发和用户群体友好的公民随时可以提供帮助。如果需要,像Katasoft这样的商业公司也可以提供专业的支持和服务。
Shiro核心概念
ApacheShiro是一个全面的、蕴含丰富功能的安全框架。
下图为描述Shiro功能的框架图:
如图所示,功能包括:
- Authentication(认证):用户身份识别,通常被称为用户“登录”
- Authorization(授权):访问控制。比如某个用户是否具有某个操作的使用权限。
- SessionManagement(会话管理):特定于用户的会话管理,甚至在非web或EJB应用程序。
- Cryptography(加密):在对数据源使用加密算法加密的同时,保证易于使用。
并且Shiro还有通过增加其他的功能来支持和加强这些不同应用环境下安全领域的关注点。
特别是对以下的功能支持:
- Web支持:Shiro提供的Web支持api,可以很轻松的保护Web应用程序的安全。
- 缓存:缓存是ApacheShiro保证安全操作快速、高效的重要手段。
- 并发:ApacheShiro支持多线程应用程序的并发特性。
- 测试:支持单元测试和集成测试,确保代码和预想的一样安全。
- “RunAs”:这个功能允许用户假设另一个用户的身份(在许可的前提下)。
- “RememberMe”:跨session记录用户的身份,只有在强制需要时才需要登录。
注意:Shiro不会去维护用户、维护权限,这些需要我们自己去设计/提供,然后通过相应的接口注入给Shiro
使用案例Demo
1.新建maven项目
为方便我们初始化项目,SpringBoot给我们提供一个项目模板生成网站。
1、打开浏览器,访问:https://start.spring.io/
2、根据页面提示,选择构建工具,开发语言,项目信息等。
2.导入springboot父依赖
org.springframework.boot spring-boot-starter-parent 2.0.2.RELEASE
3.相关jar包
web包
org.springframework.boot spring-boot-starter-web
shiro-spring包就是此篇文章的核心
shiro注解会用到aop org.apache.shiro shiro-spring 1.4.0 数据库相关包使用的是mybatisplus org.springframework.boot spring-boot-starter-aop com.alibaba druid 1.1.12 mysql mysql-connector-java com.baomidou mybatis-plus-boot-starter 3.1.0 com.baomidou mybatis-plus-generator 3.1.0 org.apache.velocity velocity-engine-core 2.0
4.数据库
建表语句在项目中有,项目地址:https://github.com/mmzsblog/mmzsblog-util
5.自定义realm
publicclassMyShiroRealmextendsAuthorizingRealm{
@Autowired
privateUserServiceuserService;
@Autowired
privateRoleServiceroleService;
@Autowired
privatePermissionServicepermissionService;
@Override
protectedAuthorizationInfodoGetAuthorizationInfo(PrincipalCollectionprincipals){
SimpleAuthorizationInfoauthorizationInfo=newSimpleAuthorizationInfo();
//HttpServletRequestrequest=(HttpServletRequest)((WebSubject)SecurityUtils
//.getSubject()).getServletRequest();//这个可以用来获取在登录的时候提交的其他额外的参数信息
Stringusername=(String)principals.getPrimaryPrincipal();
//受理权限
//角色
Setroles=newHashSet();
Rolerole=roleService.getRoleByUserName(username);
System.out.println(role.getRoleName());
roles.add(role.getRoleName());
authorizationInfo.setRoles(roles);
//权限
Setpermissions=newHashSet();
Listquerypermissions=permissionService.getPermissionsByRoleId(role.getId());
for(Permissionpermission:querypermissions){
permissions.add(permission.getPermissionName());
}
authorizationInfo.setStringPermissions(permissions);
returnauthorizationInfo;
}
@Override
protectedAuthenticationInfodoGetAuthenticationInfo(AuthenticationTokenauthcToken)
throwsAuthenticationException{
StringloginName=(String)authcToken.getPrincipal();
//获取用户密码
Useruser=userService.getOne(newQueryWrapper().eq("username",loginName));
if(user==null){
//没找到帐号
thrownewUnknownAccountException();
}
Stringpassword=newString((char[])authcToken.getCredentials());
Stringinpass=(newMd5Hash(password,user.getUsername())).toString();
if(!user.getPassword().equals(inpass)){
thrownewIncorrectCredentialsException();
}
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
SimpleAuthenticationInfoauthenticationInfo=newSimpleAuthenticationInfo(loginName,user.getPassword(),
ByteSource.Util.bytes(loginName),getName());
returnauthenticationInfo;
}
}
6.shiro配置类
@Configuration
publicclassShiroConfiguration{
privatestaticfinalLoggerlogger=LoggerFactory.getLogger(ShiroConfiguration.class);
/**
*Shiro的Web过滤器Factory命名:shiroFilter
*/
@Bean(name="shiroFilter")
publicShiroFilterFactoryBeanshiroFilterFactoryBean(SecurityManagersecurityManager){
ShiroFilterFactoryBeanshiroFilterFactoryBean=newShiroFilterFactoryBean();
//Shiro的核心安全接口,这个属性是必须的
shiroFilterFactoryBean.setSecurityManager(securityManager);
//需要权限的请求,如果没有登录则会跳转到这里设置的url
shiroFilterFactoryBean.setLoginUrl("/login.html");
//设置登录成功跳转url,一般在登录成功后自己代码设置跳转url,此处基本没用
shiroFilterFactoryBean.setSuccessUrl("/main.html");
//设置无权限跳转界面,此处一般不生效,一般自定义异常
shiroFilterFactoryBean.setUnauthorizedUrl("/error.html");
MapfilterMap=newLinkedHashMap<>();
//filterMap.put("authc",newAjaxPermissionsAuthorizationFilter());
shiroFilterFactoryBean.setFilters(filterMap);
/*
*定义shiro过滤链Map结构
*Map中key(xml中是指value值)的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的
*anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种
*authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.
*FormAuthenticationFilter
*/
MapfilterChainDefinitionMap=newLinkedHashMap<>();
/*
*过滤链定义,从上向下顺序执行,一般将/**放在最为下边;authc:所有url都必须认证通过才可以访问;
*anon:所有url都都可以匿名访问
*/
filterChainDefinitionMap.put("/login.html","authc");
filterChainDefinitionMap.put("/login","anon");
filterChainDefinitionMap.put("/js/**","anon");
filterChainDefinitionMap.put("/css/**","anon");
filterChainDefinitionMap.put("/logout","logout");
filterChainDefinitionMap.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
returnshiroFilterFactoryBean;
}
/**
*权限管理
*/
@Bean
publicSecurityManagersecurityManager(){
logger.info("=======================shiro=======================");
DefaultWebSecurityManagersecurityManager=newDefaultWebSecurityManager();
securityManager.setRealm(MyShiroRealm());
//securityManager.setRememberMeManager(rememberMeManager);
returnsecurityManager;
}
/**
*ShiroRealm继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的
*/
@Bean
publicMyShiroRealmMyShiroRealm(){
MyShiroRealmuserRealm=newMyShiroRealm();
userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
returnuserRealm;
}
/**
*凭证匹配器密码验证
*/
@Bean(name="credentialsMatcher")
publicHashedCredentialsMatcherhashedCredentialsMatcher(){
HashedCredentialsMatcherhashedCredentialsMatcher=newHashedCredentialsMatcher();
//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashAlgorithmName("md5");
//散列的次数,比如散列两次,相当于md5(md5(""));
hashedCredentialsMatcher.setHashIterations(1);
//storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
returnhashedCredentialsMatcher;
}
/**
*开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
*/
@Bean
publicAuthorizationAttributeSourceAdvisorauthorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisorauthorizationAttributeSourceAdvisor=newAuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
returnauthorizationAttributeSourceAdvisor;
}
}
7.测试类
@RestController
publicclassUserController{
@PostMapping("login")
publicStringname(Stringusername,Stringpassword){
Stringresult="已登录";
SubjectcurrentUser=SecurityUtils.getSubject();
UsernamePasswordTokentoken=newUsernamePasswordToken(username,password);
if(!currentUser.isAuthenticated()){
try{
currentUser.login(token);//会触发com.shiro.config.MyShiroRealm的doGetAuthenticationInfo方法
result="登录成功";
}catch(UnknownAccountExceptione){
result="用户名错误";
}catch(IncorrectCredentialsExceptione){
result="密码错误";
}
}
returnresult;
}
@GetMapping("logout")
publicvoidlogout(){
SubjectcurrentUser=SecurityUtils.getSubject();
currentUser.logout();
}
@RequiresPermissions("role:update")
@GetMapping("/role")
publicStringname(){
return"hello";
}
@RequiresPermissions("user:select")
@GetMapping("/role2")
publicStringpermission(){
return"hellosel";
}
}
7.1登录测试
数据库账号(密码经过md5加盐加密)
7.2权限测试
8.说明
8.1无权限时的处理
无权限时自定义了一个异常。所以,权限测试的时候没有权限就会提示配置的提示语“没有权限”。
@ControllerAdvice
publicclassShiroException{
@ExceptionHandler(value=UnauthorizedException.class)
@ResponseBody
publicStringname(){
return"没有权限";
}
}
8.2角色权限测试与权限测试相同
权限设置可在shiro配置类中shiro过滤链设置,也可用注解方式设置,本文使用注解方式。
8.3shiro的session和cache
shiro的session和cache管理可以自定义,本文用的是默认的,推荐自定义,方便管理。
小结
- ApacheShiro是Java的一个安全框架
- Shiro是一个强大的简单易用的Java安全框架,主要用来更便捷的认证、授权、加密、会话管理、与Web集成、缓存等
- Shiro使用起来小而简单
- spring中有springsecurity,是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。
- shiro不依赖于spring,shiro不仅可以实现web应用的权限管理,还可以实现c/s系统,分布式系统权限管理,
- shiro属于轻量框架,越来越多企业项目开始使用shiro.
参考:
http://shiro.apache.org/
https://www.cnblogs.com/joker-dj/archive/2020/04/13/12690648.html
到此这篇关于springboot2.x整合shiro权限框架的使用的文章就介绍到这了,更多相关springboot2.x整合shiro内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。