1. 程式人生 > 其它 >springboot整合Shiro安全框架實現許可權控制

springboot整合Shiro安全框架實現許可權控制

技術標籤:框架

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;
    }