Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。学习成本比spring-security要低很多。
shiro有三个核心组件:Subject, SecurityManager 和 Realms
Subject: 即“当前操作用户”, 它仅仅意味着“当前跟软件交互的东西”。
SecurityManager : 安全管理器,则管理所有用户的安全操作。
Realms:充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。
本文使用springboot和shiro集成,做一个小demo,分享如何简单的应用shiro。
总共分成以下步骤:
第一步,创建springboot工程,引入shiro依赖
创建springboot工程可以参考我的这篇文章https://blog.csdn.net/weixin_45415885/article/details/100864980
springboot工程创建好之后 在pom.xml中引入shiro依赖,‘
<!-- shiro 安全框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
第二步,自定义realm类,继承AuthorizingRealm
重写两个方法
doGetAuthorizationInfo : 用来执行授权逻辑
doGetAuthenticationInfo: 用来执行认证(登录)用户逻辑
具体代码如下:
package com.example.springshirodemo1.shiro;
import com.example.springshirodemo1.entity.SysUser;
import com.example.springshirodemo1.mapper.UserMapper;
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.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import javax.annotation.Resource;
import java.util.List;
public class CustomRealm extends AuthorizingRealm {
@Resource
UserMapper userMapper;
//执行授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑:doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Subject subject = SecurityUtils.getSubject();
SysUser user = (SysUser)subject.getPrincipal();
List<String> permission = userMapper.findAclByUserId(user.getId());
info.addStringPermissions(permission);
return info;
}
//执行认证逻辑(登录逻辑)
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证(登录)逻辑:doGetAuthenticationInfo");
//判断用户名和密码
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
SysUser user = userMapper.findByUsername(token.getUsername()); //通过用户名查询用户信息
if (user == null){ //如果为空,证明没有改用户
return null; //返回null代表用户不存在
}
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}
第三步,编写Shiro配置类,配置相关的bean
package com.example.springshirodemo1.config;
import com.example.springshirodemo1.shiro.CustomRealm;
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;
@Configuration
public class ShiroConfig {
/**
* Subject: 用户主体 --- 把操作交给 manager
* SecurityManager: 安全管理器--关联Realm
* Realm: shiro连接数据的桥梁
*/
//创建ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
/*
* 添加过滤器
* anon: 无需登录可以访问
* authc: 必须得到登录认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*/
Map<String,String> filterMap = new LinkedHashMap();
filterMap.put("/user/add","perms[user:add]");
filterMap.put("/user/update","perms[user:update]");
filterMap.put("/user/*","anon");
filterMap.put("/*","anon");
shiroFilterFactoryBean.setUnauthorizedUrl("/user/unAthor"); //如果不在url前面加 / ,默认把当前的请求URL加进来,会包404
shiroFilterFactoryBean.setLoginUrl("/user/unLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
//创建DefaultWebSecurityManager
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("customRealm") CustomRealm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
//创建Realm
@Bean(name = "customRealm")
public CustomRealm getCustomRealm(){
return new CustomRealm(); //new刚才自定义的realm
}
}
第四步,编写测试的controller进行验证
package com.example.springshirodemo1.controller;
import org.apache.shiro.SecurityUtils;
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.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
public String login(@RequestBody Map map){
String username = map.get("username")+""; //获取登录账号和密码
String password = map.get("password")+"";
Subject subject = SecurityUtils.getSubject(); //通过SecurityUtils得到subject
UsernamePasswordToken token = new UsernamePasswordToken(username, password); //获取token
try {
subject.login(token); //验证是否能登录
return "登录成功";
}catch (UnknownAccountException e){
return "用户名不存在!";
}catch (IncorrectCredentialsException e){
return "密码错误!";
}catch (Exception e){
return "未知异常!"+e.getMessage();
}
}
@RequestMapping("add")
public String add(){
return "添加成功!";
}
@RequestMapping("update")
public String update(){
return "修改成功!";
}
@RequestMapping("/unAthor")
public String unAthor(){
return "您没有权限访问!";
}
@RequestMapping("/unLogin")
public String unLogin(){
return "您没有登录!";
}
}
测试结果
1,没有登录就访问user/add进行增加操作,则提示“您没有登录!”
2,当前用户没有权限则提示“您没有权限访问!”
3,当用户有权限时,则访问成功