springboot整合shiro


一.數據庫這塊的准備需要創建五張表

數據庫有用戶(user)、角色(role)、權限(permission)三個實體,除了實體表以外,為了實現表間用戶與角色、角色與權限多對多的表間關系,所以產生了user_role、role_permission兩張關系表。在下圖中,使用紅線將表的外鍵標記了出來,但為了方便並沒有在表中創建外鍵,我們手動進行維護

再簡單介紹下數據庫字段,user表中name是用戶名,password是密碼;role表中name是角色名(如user、vip);permission表中,name是權限名(如會員中心),url是實際的權限字段(user:vip)

對應的sql腳本

  

/*
SQLyog Professional v12.08 (64 bit)
MySQL - 5.0.96-community-nt : Database - lastpass
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`lastpass` /*!40100 DEFAULT CHARACTER SET utf8 */;

USE `lastpass`;

/*Table structure for table `permission` */

DROP TABLE IF EXISTS `permission`;

CREATE TABLE `permission` (
  `id` varchar(255) NOT NULL,
  `name` varchar(100) default NULL,
  `url` varchar(100) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `permission` */

insert  into `permission`(`id`,`name`,`url`) values ('1','用戶中心','user:add'),('2','會員中心','user:vip');

/*Table structure for table `role` */

DROP TABLE IF EXISTS `role`;

CREATE TABLE `role` (
  `id` varchar(50) NOT NULL,
  `name` varchar(100) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `role` */

insert  into `role`(`id`,`name`) values ('1','user'),('2','vip');

/*Table structure for table `role_permission` */

DROP TABLE IF EXISTS `role_permission`;

CREATE TABLE `role_permission` (
  `id` varchar(255) NOT NULL,
  `role_id` varchar(255) NOT NULL,
  `permission_id` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `role_permission` */

insert  into `role_permission`(`id`,`role_id`,`permission_id`) values ('1','1','1'),('2','2','2');

/*Table structure for table `user` */

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` varchar(255) NOT NULL,
  `name` varchar(255) default NULL,
  `password` varchar(255) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `user` */

insert  into `user`(`id`,`name`,`password`) values ('1','rhine','28e5ea71eb6600afb02132dcf27b8e75'),('2','vip','01ffb6fc48048d105ba5061f8df5a35e');

/*Table structure for table `user_role` */

DROP TABLE IF EXISTS `user_role`;

CREATE TABLE `user_role` (
  `id` varchar(255) NOT NULL,
  `user_id` varchar(255) NOT NULL,
  `role_id` varchar(255) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `user_role` */

insert  into `user_role`(`id`,`user_id`,`role_id`) values ('1','1','1'),('2','2','1'),('3','2','2');

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

二.創建springboot項目

  1.添加shiro的依賴

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

   2.創建實體

package com.rhine.blog.po;

import java.io.Serializable;

/**
 * @description 權限類
 */
public class PermissionBean implements Serializable {

    private String id;
    private String name;
    private String url;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}




package com.rhine.blog.po;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
/**
 * @description 角色類
 */
public class RoleBean implements Serializable {
    private String id;
    private String name;
    private Set<PermissionBean> permissions = new HashSet<>();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<PermissionBean> getPermissions() {
        return permissions;
    }

    public void setPermissions(Set<PermissionBean> permissions) {
        this.permissions = permissions;
    }
}



package com.rhine.blog.po;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * @description 用戶類
 */
public class UserBean implements Serializable {
    private String id;
    private String name;
    private String password;
    private Set<RoleBean> roles = new HashSet<>();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Set<RoleBean> getRole() {
        return roles;
    }

    public void setRole(Set<RoleBean> roles) {
        this.roles = roles;
    }
}


 3.創建shiro的配置類userRealm和shiroConfig

import com.rhine.blog.po.PermissionBean;
import com.rhine.blog.po.RoleBean;
import com.rhine.blog.po.UserBean;
import com.rhine.blog.service.UserService;
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.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 授權
     **/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Subject subject = SecurityUtils.getSubject();
        UserBean user = (UserBean)subject.getPrincipal();
        if(user != null){
        	//用戶已經完成登錄 給資源進行授權
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 角色與權限字符串集合
            Collection<String> rolesCollection = new HashSet<>();
            Collection<String> premissionCollection = new HashSet<>();

            Set<RoleBean> roles = user.getRole();
            for(RoleBean role : roles){
                rolesCollection.add(role.getName());
                Set<PermissionBean> permissions = role.getPermissions();
                for (PermissionBean permission : permissions){
                    premissionCollection.add(permission.getUrl());
                }
               //添加資源的授權字符串 這塊欣慰shiroConfig配置文件中添加了需要授權的過濾器,所有需要保持一致
               //這塊的需要與shiro類中filterMap.put("/vip/index", "perms[user:vip]")
               //的保持一致才能起到授權的效果;
                info.addStringPermissions(premissionCollection);
            }
            info.addRoles(rolesCollection);
            return info;
        }
        return null;
    }

    /**
     * 認證
     **/
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    	//獲取用戶的名字
        String userName =(String)authenticationToken.getPrincipal();
        //通過用戶名獲得user對象
        UserBean bean = userService.findByName(userName);
        if(bean == null){
            throw new UnknownAccountException();
        }
        
		ByteSource byteSource = ByteSource.Util.bytes(bean.getName());
		// 交給AuthenticatingRealm使用CredentialsMatcher進行密碼匹配,如果覺得人家的不好可以自定義實現
		SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(bean, bean.getPassword(),byteSource, bean.getName());
        return authenticationInfo;
    }

}
package com.rhine.blog.config;

import com.rhine.blog.realm.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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;

/**
 * @author chenyuyu
 * @description Shiro配置類
 * @date Created in 16:07 2018/12/6
 * @modified By:
 */
@Configuration
public class ShiroConfig {

    @Bean("hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //指定加密方式為MD5
        credentialsMatcher.setHashAlgorithmName("MD5");
        //加密次數
        credentialsMatcher.setHashIterations(1024);
        credentialsMatcher.setStoredCredentialsHexEncoded(true);
        return credentialsMatcher;
    }

    @Bean("userRealm")
    public UserRealm userRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher matcher) {
        UserRealm userRealm = new UserRealm();
        userRealm.setCredentialsMatcher(matcher);
        return userRealm;
    }

    @Bean
    public ShiroFilterFactoryBean shirFilter(@Qualifier("securityManager")DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 設置 SecurityManager
        bean.setSecurityManager(securityManager);

        bean.setSuccessUrl("/main");
        // 設置登錄跳轉頁面
        bean.setLoginUrl("/toLogin");
        // 設置未授權提示頁面
        bean.setUnauthorizedUrl("/error/unAuth");
        /**
         * Shiro內置過濾器,可以實現攔截器相關的攔截器
         *    常用的過濾器:
         *      anon:無需認證(登錄)可以訪問
         *      authc:必須認證才可以訪問
         *      user:如果使用rememberMe的功能可以直接訪問
         *      perms:該資源必須得到資源權限才可以訪問
         *      role:該資源必須得到角色權限才可以訪問
         *      
         *      //授權過濾器
		//注意:當前授權攔截后,shiro會自動跳轉到未授權頁面
		filterMap.put("/add", "perms[user:add]");
		filterMap.put("/update", "perms[user:update]");
         *      
         *      
         **/
        Map<String, String> filterMap = new LinkedHashMap<>();

        filterMap.put("/login","anon");
        filterMap.put("/user/index","authc");
        //filterMap.put("/vip/index","roles[vip]");
        //filterMap.put("/vip/index","roles[user]");
        filterMap.put("/druid/**", "anon");
        filterMap.put("/static/**","anon");
        //filterMap.put("/vip/index", "perms[user:vip]");
        filterMap.put("/**","authc");
        filterMap.put("/logout", "logout");

        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }

    /**
     * 注入 securityManager
     */
    @Bean(name="securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(HashedCredentialsMatcher hashedCredentialsMatcher) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 關聯realm.
        securityManager.setRealm(userRealm(hashedCredentialsMatcher));
        return securityManager;
    }
}

認證對應的controller

package com.rhine.blog.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.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Controller
public class MainController {
	/**
	 * 登錄后進入首頁
	 * @param request
	 * @param response
	 * @return
	 */

    @RequestMapping("/main")
    public String index(HttpServletRequest request, HttpServletResponse response){
        response.setHeader("root", request.getContextPath());

        return "index";
    }
    /**
              * 進入登陸頁面
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/toLogin")
    public String toLogin(HttpServletRequest request, HttpServletResponse response){
        response.setHeader("root", request.getContextPath());

        return "login";
    }
    
    /**
             * 登錄訪問的頁面
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/login")
    public String login(HttpServletRequest request, HttpServletResponse response){
        response.setHeader("root", request.getContextPath());
        String userName = request.getParameter("username");
        String password = request.getParameter("password");

        if(!StringUtils.isEmpty(userName)){
            // 1.獲取Subject
            Subject subject = SecurityUtils.getSubject();
            // 2.封裝用戶數據
            UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
            // 3.執行登錄方法
            try{
                subject.login(token); //訪問UserRealm中doGetAuthenticationInfo方法
                return "redirect:/main";
            } catch (UnknownAccountException e){
                System.out.println("用戶名不存在!");
                request.setAttribute("msg","用戶名不存在!");
            } catch (IncorrectCredentialsException e){
                System.out.println("密碼錯誤!");
                request.setAttribute("msg","密碼錯誤!");
            }
        }

        return "login";
    }
    /**
          * 推出登錄
     * @return
     */
    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        if (subject != null) {
            subject.logout();
        }
        return "redirect:/main";
    }

    @RequestMapping("/error/unAuth")
    public String unAuth(){
        return "/error/unAuth";
    }
}

權限控制對應的controller

package com.rhine.blog.controller;

import com.rhine.blog.po.UserBean;
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class UserController {

    @RequestMapping("/user/index")
    public String add(HttpServletRequest request){
        UserBean bean = (UserBean) SecurityUtils.getSubject().getPrincipal();
        request.setAttribute("userName", bean.getName());
        return "/user/index";
    }

    @RequestMapping("/vip/index")
    public String update(){
        return "/vip/index";
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM