spring boot +shiro+mybaits 多數據源項目搭建【二】shiro 整合


上一章:https://blog.csdn.net/qq_41780372/article/details/104823854 

一、修改生成的實體,創建查詢用戶信息的方法

1.一個用戶是對應多個角色,一個角色對應多個權限(菜單)。
我們在用戶實體上面新增一個角色集合 SysUser.java

  List<SysRole> roles;

在角色上面增加權限集合 SysRole.java

 List<SysMenu> sysMenus;

 記得兩個屬性上面均需要加上註解@TableField(exist = false),否則在查詢數據庫時mybaits-plus會把這個當做一個數據庫字段進行查詢。

2.新增加一個登陸的service,創建一個根據用戶名查用戶及所有角色和權限的方法。

SysLoginService.java內增加一個接口
SysUser getUserByName(String username);
SysLoginServiceImpl.java內實現接口
@Service
public class SysLoginServiceImpl implements SysLoginService {

    @Autowired
    private SysUserServiceImpl sysUserService;
    @Autowired
    private SysRoleServiceImpl sysRoleService;
    @Autowired
    private SysRoleMenuServiceImpl sysRoleMenuService;
    @Autowired
    private SysMenuServiceImpl sysMenuService;
    @Autowired
    private SysUserRoleServiceImpl sysUserRoleService;

    @Override
    public SysUser getUserByName(String username) {
        SysUser sysUser=sysUserService.getOne(new QueryWrapper<SysUser>().eq("username",username));
        if(sysUser!=null){
            List<SysUserRole> sysUserRoles=sysUserRoleService.list(new QueryWrapper<SysUserRole>().eq("user_id",sysUser.getUserId()));
            List<SysRole> sysRoles=new ArrayList<>();
            for(SysUserRole sysUserRole:sysUserRoles){
                SysRole sysRole=sysRoleService.getById(sysUserRole.getRoleId());
                List<SysMenu> sysMenuList=new ArrayList<>();
                List<SysRoleMenu> roleMenuList=sysRoleMenuService.list(new QueryWrapper<SysRoleMenu>().eq("role_id",sysUserRole.getRoleId()));
                for(SysRoleMenu sysRoleMenu:roleMenuList){
                    sysMenuList.add(sysMenuService.getById(sysRoleMenu.getMenuId()));
                }
                sysRole.setSysMenus(sysMenuList);
                sysRoles.add(sysRole);
            }
            sysUser.setRoles(sysRoles);
        }
        return sysUser;
    }
}

二、編輯shiro的配置。

編輯CustomRealm.java

package cn.mvapi.xiaobao.common.shiro;



import cn.mvapi.xiaobao.common.system.entity.SysMenu;
import cn.mvapi.xiaobao.common.system.entity.SysRole;
import cn.mvapi.xiaobao.common.system.entity.SysUser;
import cn.mvapi.xiaobao.common.system.service.SysUserService;
import cn.mvapi.xiaobao.common.system.service.impl.SysLoginServiceImpl;
import cn.mvapi.xiaobao.common.system.service.impl.SysUserServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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;


public class CustomRealm extends AuthorizingRealm {

    @Autowired
    private SysLoginServiceImpl sysLoginService;
    @Autowired
    private SysUserServiceImpl sysUserService;
    //進入角色授權 該方法是將用戶的角色及權限全部查出來
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //獲取登錄用戶名
        String username = (String) principalCollection.getPrimaryPrincipal();
        //根據用戶名去數據庫查詢用戶信息
        SysUser sysUser = sysLoginService.getUserByName(username);//new QueryWrapper<SysUser>().eq("username",username));
        //添加角色和權限
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        for (SysRole role : sysUser.getRoles()) {
            //添加角色
            simpleAuthorizationInfo.addRole(role.getRoleName());
            //添加權限
            for (SysMenu sysMenu : role.getSysMenus()) {
                if(sysMenu.getPerms()!=null&&!sysMenu.getPerms().trim().equals("")){
                    for(String str:sysMenu.getPerms().split(",")){
                        simpleAuthorizationInfo.addStringPermission(str);
                    }
                }
            }
        }
        return simpleAuthorizationInfo;
    }
    
    //主要用於賬號密碼校驗,通過用戶名查出數據庫內的密碼,交給shiro校驗
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //加這一步的目的是在Post請求的時候會先進認證,然後在到請求
        if (authenticationToken.getPrincipal() == null) {
            return null;
        }
        //獲取用戶信息
        String name = authenticationToken.getPrincipal().toString();
        SysUser user =  sysUserService.getOne(new QueryWrapper<SysUser>().eq("username",name));

        if (user == null) {
            //這裏返回後會報出對應異常
            return null;
        } else {
            //這裏驗證authenticationToken和simpleAuthenticationInfo的信息
            //用戶名–此處傳的是用戶對象
            //密碼—從數據庫中獲取的密碼
            //getName() //當前的realm名
            SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
            return simpleAuthenticationInfo;
        }
    }
}

 

shiro配置  ShiroConfig.java 
將上面的自定義realm添加到容器內,另外如果有多種校驗方式可以添加多個realm。

配置攔截的路徑和跳轉條件。

package cn.mvapi.xiaobao.common.shiro;



import org.apache.shiro.mgt.SecurityManager;
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.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    //不加這個註解不生效,具體不詳
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    //將自己的驗證方式加入容器
    @Bean
    public CustomRealm myShiroRealm() {
        CustomRealm customRealm = new CustomRealm();
        return customRealm;
    }

    //權限管理,配置主要是Realm的管理認證
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        return securityManager;
    }

    //Filter工廠,設置對應的過濾條件和跳轉條件
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new HashMap<>();
        map.put("/test/**","anon");
        map.put("/public/**","anon");
        map.put("/plugin/**","anon");
        //登出
        map.put("/logout", "logout");
        //對所有用戶認證
        map.put("/admin/**", "authc");
        map.put("/user/**", "authc");
        //登錄
        shiroFilterFactoryBean.setLoginUrl("/login/index.html");
        //首頁
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //錯誤頁面,認證不通過跳轉
        shiroFilterFactoryBean.setUnauthorizedUrl("/login/index.html");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    //加入註解的使用,不加入這個註解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

三、編輯登錄功能,測試功能是否正常。

1.編輯通用的數據返回實體。ReturnData.java
會使用枚舉的話這裏也可以用上。

public class ReturnData {
    private int code;
    private String msg;
    private Object date;

    public ReturnData() {

    }

    public ReturnData(int code, String msg, Object date) {
        this.code = code;
        this.msg = msg;
        this.date = date;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getDate() {
        return date;
    }

    public void setDate(Object date) {
        this.date = date;
    }
}

編輯登錄控制器及相應的權限測試方法。SysLoginController.java

package cn.mvapi.xiaobao.common.system.controller;


import cn.mvapi.xiaobao.common.system.entity.ReturnData;
import cn.mvapi.xiaobao.common.system.entity.SysUser;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

//import com.sun.jndi.toolkit.url.UrlUtil;
//import org.apache.commons.codec.net.URLCodec;

@Controller
public class SysLoginController {
    @ResponseBody
    @RequestMapping("/login")
    public ReturnData login(SysUser user) {
        //添加用戶認證信息
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
                user.getUsername(),
                user.getPassword()
        );
        String error="";
        try {
            //進行驗證,這裏可以捕獲異常,然後返回對應信息
            subject.login(usernamePasswordToken);
//            subject.checkRole("admin");
 //           subject.checkPermissions("query", "add");
        } catch (AuthenticationException e) {
            //e.printStackTrace();
           // return "賬號或密碼錯誤!";
           return new ReturnData(201,"賬號或密碼錯誤!",null);
        } catch (AuthorizationException e) {
           // e.printStackTrace();
            return new ReturnData(202,"您沒有權限!",null);
            // return "沒有權限";
        }
        return new ReturnData(200,"登錄成功!",null);
    }
    //註解驗角色和權限
    @RequiresPermissions("sys:role:delete")
    @RequestMapping("/delete")
    @ResponseBody
    public String index() {
        return "delete";
    }


    @RequiresPermissions("sys:user:save")
    @RequestMapping("/save")
    @ResponseBody
    public String save() {
        return "save";
    }

    //@RequiresPermissions("sys:user:save")
    @RequiresRoles("管理員")
    @RequestMapping("/role")
    @ResponseBody
    public String role() {
        return "role";
    }

    @RequiresPermissions("sys:role:otherpermission")
    @RequestMapping("/otherPermission")
    @ResponseBody
    public String others() {
        return "用戶不存在的權限";
    }

    @RequiresRoles("otherRoles")
    @RequestMapping("/otherRoles")
    @ResponseBody
    public String otherRoles() {
        return "用戶不存在的角色";
    }
}

啓動項目測試功能是否正常。
未登錄情況下訪問這裏會拋出錯誤http://localhost:8081/save 
 

訪問登錄接口:http://localhost:8081/login/?username=admin&password=123 

提示登錄成功後再次訪問上面接口 ,界面顯示save代表正常。
訪問http://localhost:8081/otherPermission

http://localhost:8081/otherRoles 系統會拋出錯誤,因爲當前用戶沒有這個角色和權限。

本次教程結束! 

上一章:https://blog.csdn.net/qq_41780372/article/details/104823854

下一章:https://blog.csdn.net/qq_41780372/article/details/105096733

github地址:https://github.com/xiaobaos/springboot

碼雲地址:https://gitee.com/xiaobaomeat/springboot

 

項目優先更新到github上面。
下一章:引入界面。 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章