欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Shiro與Springboot整合開發(fā)的基本步驟過程詳解

 更新時間:2023年06月30日 09:17:13   作者:流光CN  
這篇文章主要介紹了Shiro與Springboot整合開發(fā)的基本步驟,本文結(jié)合實例代碼給大家介紹整合過程,感興趣的朋友跟隨小編一起看看吧

前言

在 Spring Boot 中做權(quán)限管理,一般來說,主流的方案是 Spring Security ,但是,僅僅從技術(shù)角度來說,也可以使用 Shiro。

一、基本開發(fā)步驟

在整合之前,讓我們先來了解一下Shiro開發(fā)的基本步驟:

1. 導(dǎo)入Shiro依賴:首先,在你的項目中添加Shiro的依賴,你可以通過Maven或者Gradle來管理項目依賴,確保你的項目中已經(jīng)引入Shiro的相關(guān)庫文件。

2. 配置Shiro: 接下來,你需要配置Shiro的一些核心組件,如安全管理器、認證器、授權(quán)器等。你可以在配置文件中添加相關(guān)的配置,或者在代碼中進行編程式配置。

3. 編寫和配置Realm: Realm是Shiro進行認證和授權(quán)的核心組件之一。你需要編寫一個實現(xiàn)了Shiro提供的Realm接口的類,并根據(jù)你的業(yè)務(wù)需求,實現(xiàn)其中的認證和授權(quán)邏輯。在Shiro的配置中,將你的Realm配置為Shiro的認證和授權(quán)來源。

4. 設(shè)計登錄和認證流程: 登錄是Shiro應(yīng)用中很重要的一部分。你可以設(shè)計一個登錄界面,接受用戶輸入的用戶名和密碼,并將其傳遞給Shiro進行認證。在認證過程中,Shiro會調(diào)用你實現(xiàn)的Realm來驗證用戶的身份信息。

5. 設(shè)計和配置授權(quán)規(guī)則: 授權(quán)是Shiro應(yīng)用中的另一個重要方面。你可以在Realm中定義角色和權(quán)限,并根據(jù)用戶的身份和角色,來控制用戶對應(yīng)用中某些資源或操作的訪問權(quán)限。在配置文件中,你可以設(shè)定哪些角色可以訪問哪些資源。

6. 集成Shiro到你的應(yīng)用: 你需要將Shiro集成到你的應(yīng)用中,以便能夠?qū)τ脩暨M行認證和授權(quán)??梢酝ㄟ^編寫過濾器、注解或者攔截器的方式,將Shiro應(yīng)用到你的業(yè)務(wù)代碼中。

7. 測試和調(diào)試: 在完成上述步驟后,你可以對應(yīng)用進行測試和調(diào)試,確保Shiro在你的應(yīng)用中正確地進行認證和授權(quán)。

8. 安全加固:最后,你可以進行一些額外的安全加固措施,如密碼加密存儲、登錄日志記錄等,以提高應(yīng)用的安全性。

二、Springboot整合開發(fā)

在這里插入圖片描述

1. 數(shù)據(jù)庫設(shè)計

可以隨意建設(shè)一個關(guān)系型數(shù)據(jù)庫的多表,完成相應(yīng)的一個屬性值與關(guān)系映射。權(quán)限設(shè)計通常采用RBAC即用戶、角色、權(quán)限、用戶-角色、角色-權(quán)限5張表。

2.前期準備

導(dǎo)入jar包,準備相應(yīng)pom.xml

 <dependency>
	  <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
       <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring-boot-starter</artifactId>
        <version>1.7.1</version>
     </dependency>
        <dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>${mybatis-plus.version}</version>
		</dependency>
	<dependency>
		<groupId>mysql</groupId>
		<artifactId>mysql-connector-java</artifactId>
		<scope>runtime</scope>
	</dependency>
	<!--druid -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>${druid.version}</version>
		</dependency>

業(yè)務(wù)實現(xiàn)可以通過通過Mybaits-plus或mybatis、Hibernate 查詢用戶的信息、用戶角色信息、用戶的權(quán)限信息。

@Service
@Transactional(rollbackFor=Exception.class)
public class UserServiceImpl implements UserService
{
    @Autowired
    private UserMapper userMapper;
    //查詢用戶信息
    @Override
    public User getUserByUserId(String userId)
    {
        Assert.notNull(userId, "userId不能為空");
        User user= userMapper.getUserByUserId(userId);
        if(user==null)
        {
            throw new UnknownAccountException("用戶名或密碼不正確");
        }
        //
        if("0".equals(user.getActive()))
        {
            throw new UnknownAccountException("用戶狀態(tài)不正確");
        }
        return user;
    }
   //獲取用戶角色
    @Override
    public List<Role> getRolesByUserOid(Integer userOid)
    {
        Assert.notNull(userOid, "userOid不能為空");
        return userMapper.getRolesByUserOid(userOid);
    }
   //獲取用戶權(quán)限
    @Override
    public List<Func> getResByRoleOid(Collection<Integer> roleOids)
    {
        Assert.notNull(roleOids, "roleOid不能為空");
        return userMapper.getResByRoleOid(roleOids);
    }
}

Dao層

public interface UserMapper extends BaseMapper<User>
{
    User getUserByUserId(String userId);
    List<Role> getRolesByUserOid(@Param("userOid")Integer userOid);
    List<Func> getResByRoleOid(@Param("roleOids")Collection<Integer> roleOids);
}

配置文件UserMapper.xml,并掃描對于該文件進行查找映射

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.skywares.fw.security.mapper.UserMapper">
<select id="getUserByUserId" resultType="com.skywares.fw.security.pojo.User">
      select 
        oid,
        userId,
        userName,
        active,
        gender,
        mobile,
        email,
        pwd        
      from fw_security_user u 
      where u.userId=#{userId}
 </select>
     <select id="getRolesByUserOid"  resultType="com.skywares.fw.security.pojo.Role">
        select 
		  r.oid,
		  r.roleId,
		  r.active,
		  r.updateUser,
		  r.updateDate
		from fw_security_user u 
		  join fw_security_user_role ur on ur.userOid = u.oid 
		  join fw_security_role r  on r.oid = ur.roleOid 
		 where u.active='1'
		   and u.oid =#{userOid}
    </select> 
      <select id="getResByRoleOid" resultType="com.skywares.fw.security.pojo.Func">
       select 
		  res.oid,
		  res.resId,
		  res.defaultLabel,
		  res.seq,
		  res.parentoid,
		  res.url,
		  res.exturl,
		  res.type,
		  res.active
        from  fw_security_res res 
		  join fw_security_role_res r on r.resOid = res.oid 
		  join fw_security_role role  on role.oid = r.roleOid 
		  where role.oid in
	         <foreach collection="roleOids" item="oid" open="(" close=")" separator=",">
	            #{oid}
	        </foreach>
		order BY res.oid desc
    </select>
</mapper>

三、Shiro的集成

自定義Realm實現(xiàn)認證

public class CustomerRealm extends AuthorizingRealm 
{
    @Autowired
    private UserService userService;
    //授權(quán)認證
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
    {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        User user = (User) principalCollection.getPrimaryPrincipal();
        Integer userOid=user.getOid();
        List<Role> roleList= userService.getRolesByUserOid(userOid);
        //用戶角色
        Set<String> roleSet=new HashSet<>();
        //權(quán)限信息
        Set<String> funcSet=new HashSet<>();
        Set<Integer> roleOids=new HashSet<>();
        //查詢角色
        if(roleList!=null && !roleList.isEmpty())
        {
            roleList.stream().forEach(t->{
                roleSet.add(String.valueOf(t.getRoleId()));
                roleOids.add(t.getOid());
            });
        }
        //查詢權(quán)限
        List<Func> funcList= userService.getResByRoleOid(roleOids);
        if(funcList!=null && !funcList.isEmpty()){
            for(Func func:funcList)
            {
                funcSet.add(func.getUrl());
            }
        }
        //添加角色
        info.addRoles(roleSet);
        //添加權(quán)限
        info.addStringPermissions(funcSet);
        return info;
    }
    //用戶認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authToken) throws AuthenticationException
    {        
        //采用用戶名和密碼方式
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authToken;
        String userId = usernamePasswordToken.getUsername();
        //密碼
        String password = new String(usernamePasswordToken.getPassword());
        // 通過用戶id獲取用戶信息
        User user = userService.getUserByUserId(userId);
        //認證。密碼進行加密處理 
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPwd(),new CustByteSource(user.getUserId()),getName());
        return info;
    }
}

其中 doGetAuthenticationInfo:實現(xiàn)用戶的認證,本文采用的是用戶名和密碼的方式。 doGetAuthorizationInfo :加載用戶的授權(quán)信息 CustByteSource: 用戶自定義的加密方式

可以自定義加密方式

public class CustByteSource implements ByteSource, Serializable
{
    private static final long serialVersionUID = -3818806283942882146L;
    private byte[] bytes;
    private String cachedHex;
    private String cachedBase64;
    public CustByteSource()
    {
    }
    public CustByteSource(byte[] bytes)
    {
        this.bytes = bytes;
    }
    public CustByteSource(char[] chars)
    {
        this.bytes = CodecSupport.toBytes(chars);
    }
    public CustByteSource(String string)
    {
        this.bytes = CodecSupport.toBytes(string);
    }
    public CustByteSource(ByteSource source)
    {
        this.bytes = source.getBytes();
    }
    public CustByteSource(File file)
    {
        this.bytes = new CustByteSource.BytesHelper().getBytes(file);
    }
    public CustByteSource(InputStream stream)
    {
        this.bytes = new CustByteSource.BytesHelper().getBytes(stream);
    }
    public static boolean isCompatible(Object o)
    {
        return o instanceof byte[] || o instanceof char[]
                || o instanceof String || o instanceof ByteSource
                || o instanceof File || o instanceof InputStream;
    }
    @Override
    public byte[] getBytes()
    {
        return this.bytes;
    }
    @Override
    public boolean isEmpty()
    {
        return this.bytes == null || this.bytes.length == 0;
    }
    @Override
    public String toHex()
    {
        if (this.cachedHex == null)
        {
            this.cachedHex = Hex.encodeToString(getBytes());
        }
        return this.cachedHex;
    }
    @Override
    public String toBase64()
    {
        if (this.cachedBase64 == null)
        {
            this.cachedBase64 = Base64.encodeToString(getBytes());
        }
        return this.cachedBase64;
    }
    @Override
    public String toString()
    {
        return toBase64();
    }
    @Override
    public int hashCode()
    {
        if (this.bytes == null || this.bytes.length == 0)
        {
            return 0;
        }
        return Arrays.hashCode(this.bytes);
    }
    @Override
    public boolean equals(Object o)
    {
        if (o == this)
        {
            return true;
        }
        if (o instanceof ByteSource)
        {
            ByteSource bs = (ByteSource) o;
            return Arrays.equals(getBytes(), bs.getBytes());
        }
        return false;
    }
    private static final class BytesHelper extends CodecSupport
    {
        /**
         * 嵌套類也需要提供無參構(gòu)造器
         */
        private BytesHelper()
        {
        }
        public byte[] getBytes(File file)
        {
            return toBytes(file);
        }
        public byte[] getBytes(InputStream stream)
        {
            return toBytes(stream);
        }
    }
}

通過shiro提供加密方式針對密碼進行加密處理,用戶注冊獲取密碼方式如下:

   public static final String md5Pwd(String salt,String pwd)
    {
        //加密方式
        String hashAlgorithmName = "MD5";
        //鹽:為了即使相同的密碼不同的鹽加密后的結(jié)果也不同
        ByteSource byteSalt = ByteSource.Util.bytes(salt);
        //加密次數(shù)
        int hashIterations = 2;
        SimpleHash result = new SimpleHash(hashAlgorithmName, pwd, byteSalt, hashIterations);
        return result.toString();
    }

Shiro核心配置

@Configuration
public class ShiroConfig
{
   // 自定義密碼加密規(guī)則
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher()
    {
        HashedCredentialsMatcher hashedCredentialsMatcher =new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(2);
        //true 代表Hex編碼,fasle代表采用base64編碼
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
        return hashedCredentialsMatcher;
    }
    // 自定義認證
    @Bean
    public CustomerRealm customerRealm()
    {
        CustomerRealm customerRealm=new  CustomerRealm();
        customerRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        customerRealm.setCachingEnabled(false);
        return customerRealm;
    }
    //需要定義DefaultWebSecurityManager,否則會報bean沖突
    @Bean
    public DefaultWebSecurityManager securityManager() 
    {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(customerRealm());
        securityManager.setRememberMeManager(null);
        return securityManager;
    }
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager)
    {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        //給filter設(shè)置安全管理
        factoryBean.setSecurityManager(securityManager);
        //配置系統(tǒng)的受限資源
        Map<String,String> map = new HashMap<>();
        //登錄請求無需認證
        map.put("/login", "anon");
        //其他請求需要認證
        map.put("/**", "authc");
        //訪問需要認證的頁面如果未登錄會跳轉(zhuǎn)到/login
        factoryBean.setLoginUrl("/login");
        //訪問未授權(quán)頁面會自動跳轉(zhuǎn)到/unAuth
        factoryBean.setUnauthorizedUrl("/unAuth");
        factoryBean.setFilterChainDefinitionMap(map);
        return factoryBean;
    }
    /**
     * 開啟注解方式,頁面可以使用注解
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
}

四、測試

// 登錄測試
@Controller
@RequestMapping("")
public class LoginController
{
   @RequestMapping("/login")
   @ResponseBody
   public String login(@RequestParam String userName,@RequestParam String password)
   {
     Subject subject = SecurityUtils.getSubject();
     UsernamePasswordToken usernamePasswordToken =new UsernamePasswordToken(userName, password);
     subject.login(usernamePasswordToken);
     return "成功";
   }
      /**
    * 用戶未登錄
    * @return
    */
   @RequestMapping("/unLogin")
   public String unLogin()
   {
     return "login.html";
   }
   /**
    * 用戶未授權(quán)
    * @return
    */
   @RequestMapping("/unAuth")
   public String unAuth()
   {
     return "unAuth.html";
   }
}
// 角色和權(quán)限測試
@RestController
@RequestMapping("/app/sys/user")
public class UserController
{
   @RequestMapping("/list")
   @RequiresPermissions("/app/sys/user/list")
   public String list()
   {
       return "成功";
   }
   @RequestMapping("/roleTest")
   @RequiresRoles("admin1")
   public String roleTest()
   {
       return "成功";
   }
   @RequestMapping("/resourceTest")
   @RequiresPermissions("/app/sys/user/list1")
   public String resourceTest()
   {
       return "成功";
   }
}

這里就做一個授權(quán)測試看一下就行了

//訪問需要認證的頁面如果未登錄會跳轉(zhuǎn)到/login路由進行登陸
factoryBean.setLoginUrl("/unLogin");

用戶訪問/login請求輸入正確的用戶名和密碼

在這里插入圖片描述

到此這篇關(guān)于Shiro與Springboot整合開發(fā)的文章就介紹到這了,更多相關(guān)Shiro與Springboot整合內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring?Boot?底層原理基礎(chǔ)深度解析

    Spring?Boot?底層原理基礎(chǔ)深度解析

    這篇文章主要介紹了Spring?Boot?底層原理基礎(chǔ),包括底層注解@Configuration,底層注解@Import及底層注解@Conditional的相關(guān)知識,本文結(jié)合示例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-04-04
  • Java開發(fā)常用類庫之Hutool詳解

    Java開發(fā)常用類庫之Hutool詳解

    這篇文章主要介紹了Java開發(fā)常用類庫之Hutool,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • Java之PreparedStatement的使用詳解

    Java之PreparedStatement的使用詳解

    這篇文章主要介紹了Java之PreparedStatement的使用詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java 并發(fā)編程的可見性、有序性和原子性

    Java 并發(fā)編程的可見性、有序性和原子性

    這篇文章主要介紹了Java 并發(fā)編程的可見性、有序性和原子性的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java并發(fā)編程,感興趣的朋友可以了解下。
    2020-11-11
  • 作為程序員必須掌握的Java虛擬機中的22個重難點(推薦0

    作為程序員必須掌握的Java虛擬機中的22個重難點(推薦0

    這篇文章主要介紹了Java虛擬機中22個重難點,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 實例詳解MyBatis-plus自動填充功能

    實例詳解MyBatis-plus自動填充功能

    每次對數(shù)據(jù)進行新增、刪除、修改時都需要對這些字段進行設(shè)置,雖然新增時間和修改時間可以使用數(shù)據(jù)庫的時間,但是新增人和修改人就不能使用這樣的功能,下面小編給大家介紹下MyBatis-plus自動填充功能的實例代碼,感興趣的朋友一起看看吧
    2022-01-01
  • ChatGPT-4.0未來已來 你來不來

    ChatGPT-4.0未來已來 你來不來

    最近聽說了一個非?;鸬募夹g(shù)ChatGPT4.0,今天這篇文章就給大家介紹一下ChatGPT究竟是什么東東,不得不說ChatGPT是真的強,下面就讓我們一起了解究竟什么是ChatGPT吧
    2023-03-03
  • Spring條件注解@ConditionnalOnClass的原理分析

    Spring條件注解@ConditionnalOnClass的原理分析

    這篇文章主要介紹了Spring條件注解@ConditionnalOnClass的原理分析,所謂@ConditionalOnClass注解,翻譯過來就是基于class的條件,它為所標注的類或方法添加限制條件,當該條件的值為true時,其所標注的類或方法才能生效,需要的朋友可以參考下
    2023-12-12
  • Springboot如何使用logback實現(xiàn)多環(huán)境配置?

    Springboot如何使用logback實現(xiàn)多環(huán)境配置?

    上一篇文章中老顧介紹了logback基本配置,了解了日志配置的基本方式.我們平時在系統(tǒng)開發(fā)時,開發(fā)環(huán)境與生產(chǎn)環(huán)境的日志配置會不一樣;那今天老顧就跟大家介紹一下如何實現(xiàn)多環(huán)境配置,需要的朋友可以參考下
    2021-06-06
  • Java?Web?Axios實現(xiàn)前后端數(shù)據(jù)異步交互實例代碼

    Java?Web?Axios實現(xiàn)前后端數(shù)據(jù)異步交互實例代碼

    Axios作為一個流行的前端?HTTP?通信庫,可以極大地簡化前端與后端之間的數(shù)據(jù)交互,這篇文章主要介紹了Java?Web?Axios實現(xiàn)前后端數(shù)據(jù)異步交互的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-09-09

最新評論