springboot整合Shiro安全框架實現許可權控制
阿新 • • 發佈:2020-12-28
技術標籤:框架
springboot整合Shiro安全框架實現許可權控制
當使用shiro安全框架驗證是否有許可權時,需要建立5張表,分別為:
資料庫表:
user
:使用者表
user_role
:使用者角色中間表
role
:角色表
role_permission
:角色許可權中間表
permission
:許可權表
實體類:user
permission
import lombok.Data;
@Data
public class User {
private Integer id;
private String userName;
private String password;
}
import lombok.Data;
@Data
public class Permission {
private Integer id;
private String permissionName;//許可權名
}
List<Permission> permissionList=findPermissionByUserName(username)
五表聯查,通過使用者名稱查出該使用者所具有的許可權。
1.引入依賴
<!--安全框架shiro-->
<dependency>
< groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
2.自定義驗證規則 MyRealm
package com.qf.realm;
import com.qf.dao.PermissionMapper;
import com.qf.dao.UserMapper;
import com.qf.pojo.Permission;
import com. qf.pojo.User;
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.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.HashSet;
import java.util.List;
public class MyRealm extends AuthorizingRealm {
@Autowired
UserMapper userMapper;
@Autowired
PermissionMapper permissionMapper;
//賦予許可權的方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//獲取到前端使用者傳入的使用者名稱
String username = (String) principalCollection.getPrimaryPrincipal();
//通過使用者名稱查詢使用者的許可權
List<Permission> permissionList = permissionMapper.findPermissionByUserName(username);
HashSet<String> set = new HashSet<>();
//去重,將許可權名加入set集合中
for (Permission permission : permissionList) {
//System.out.println(permission.toString());
set.add(permission.getPermissionName());
}
//宣告SimpleAuthorizationInfo
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//將許可權設定到該物件中
simpleAuthorizationInfo.setStringPermissions(set);
//返回授權資訊
return simpleAuthorizationInfo;
}
//使用者認證的方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//獲取到前端使用者傳入的使用者名稱
String username = (String) authenticationToken.getPrincipal();
//使用前端的使用者名稱查詢使用者密碼
User byUserName = userMapper.findByUserName(username);
if(byUserName != null){
//宣告SimpleAuthenticationInfo 將前端傳入的使用者名稱,以及從資料庫查詢楚的密碼
//以及當前類的名稱放置生成SimpleAuthenticationInfo 進行返回
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,byUserName.getPassword(),getName());
//返回身份認證資訊
return simpleAuthenticationInfo;
}
return null;
}
}
3.建立配置類 ShiroConfig
package com.qf.config;
import com.qf.realm.MyRealm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//標註當前類是配置類
@Configuration
public class ShiroConfig {
//宣告自定義好的Reslm name = "方法名"
@Bean(name = "myRealm")
public MyRealm myRealm(){
return new MyRealm();
}
//shiro 核心控制器,將自定義驗證交給核心
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("myRealm")MyRealm myRealm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//將自定義驗證交給核心
defaultWebSecurityManager.setRealm(myRealm);
return defaultWebSecurityManager;
}
//宣告shiro的Bean工廠,將核心進行設定
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
return shiroFilterFactoryBean;
}
//開啟shiro許可權的註解模式
//授權屬性來源顧問
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
return authorizationAttributeSourceAdvisor;
}
//預設顧問自動代理建立者
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator;
}
}
4.設定訪問許可權
在controller中的方法加入@RequiresPermissions(value = {“訪問路徑”}),如下所示:
@RequiresPermissions(value = {"/book/findAll"})//訪問需要許可權findAll
@RequestMapping(value = "/findAll/{page}/{size}",method = RequestMethod.GET)
public BaseResp findAll(@PathVariable("page")Integer page,@PathVariable("size")Integer size){
return bookService.findAll(page,size);
}
此時前端請求方法,需要通過shiro安全框架驗證,通過後允許訪問,否則沒有許可權,會丟擲UnauthorizedException異常,當沒有登入會丟擲UnauthenticatedException異常。
5.抓取丟擲的異常
package com.qf.gloableExcepiton;
import com.qf.common.BaseResp;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
@ResponseBody
public class ExcepitonController {
@ExceptionHandler(UnauthorizedException.class)
public BaseResp AuthonewrizationEx(){
BaseResp BaseResp = new BaseResp();
BaseResp.setCode(300);
BaseResp.setMessage("無許可權訪問");
return BaseResp;
}
@ExceptionHandler(UnauthenticatedException.class)
public BaseResp unauthenticatedException(){
BaseResp BaseResp = new BaseResp();
BaseResp.setCode(400);
BaseResp.setMessage("未登入");
return BaseResp;
}
}
前端通過返回的資料,判斷,進行跳轉頁面等。
6…登入驗證serviceImpl寫法
@Autowired
UserMapper userMapper;
@Autowired
RedisUtils redisUtils;
@Override
public BaseResp login(User user) {
//登入的驗證。從subjectUtils中獲取主體
Subject subject = SecurityUtils.getSubject();
//將前端輸入的使用者名稱以及密碼設定到UserNameAndPasswordToken令牌中
UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassword());
BaseResp baseResp = new BaseResp();
//使用主體將token令牌放置,進行驗證
//IncorrectCredentialsException 密碼不正確的異常通知
//UnknownAccountException 使用者名稱不正確的異常
try {
subject.login(token);
//其他的業務邏輯,放置到session,redis中等等
//判斷該使用者是否登入
if(subject.isAuthenticated()){
//rddis資料庫中的key
UUID uuid = UUID.randomUUID();
//將使用者名稱和密碼存入Redis資料庫中
redisUtils.set(uuid.toString(),userMapper.findByUserName(user.getUserName()));
baseResp.setData(uuid.toString());
baseResp.setCode(200);
baseResp.setMessage("登入成功!");
return baseResp;
}
}catch (UnknownAccountException ex){
baseResp.setCode(201);
baseResp.setMessage("使用者名稱不存在");
return baseResp;
}catch (IncorrectCredentialsException ex){
baseResp.setCode(202);
baseResp.setMessage("使用者密碼不正確");
return baseResp;
}
return baseResp;
}