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

springboot結(jié)合shiro實(shí)現(xiàn)身份認(rèn)證的實(shí)戰(zhàn)

 更新時(shí)間:2025年10月24日 10:18:27   作者:剽悍一小兔  
本文主要介紹了springboot結(jié)合shiro實(shí)現(xiàn)身份認(rèn)證的實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

hello,大家好,我們寫(xiě)任何企業(yè)級(jí)項(xiàng)目基本都會(huì)需要做權(quán)限,權(quán)限包含身份認(rèn)證和授權(quán)。

所謂身份認(rèn)證,就是證明你是你。

所謂授權(quán)就是明白你登錄之后能干什么。

現(xiàn)在,讓我們用springboot項(xiàng)目入手,結(jié)合shiro框架來(lái)完成這一切。

環(huán)境搭建

基本信息:

springboot版本:

初始其他依賴:

創(chuàng)建完畢:

添加Shiro和Spring Boot的依賴項(xiàng)。在你的pom.xml文件中添加以下依賴項(xiàng):

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-starter</artifactId>
    <version>1.7.1</version>
</dependency>

配置shiro環(huán)境

第一步,創(chuàng)建一個(gè)Shiro的配置類(lèi)。

創(chuàng)建一個(gè)類(lèi),并使用@Configuration注解標(biāo)記它。在該類(lèi)中,你可以配置Shiro的相關(guān)設(shè)置,例如Realm、Session管理器等。

配置代碼如下:

package com.it.shirodemo.config;

import com.it.shirodemo.realm.MyRealm;
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.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
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;

@Configuration
public class ShiroConfig {

    @Bean
    public MyRealm myRealm(){
        return new MyRealm();
    }


    @Bean(name = "mySecurityManager")
    public DefaultWebSecurityManager  securityManager(@Qualifier("myRealm") MyRealm myRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        return securityManager;
    }

    /**
     * 路徑過(guò)濾規(guī)則
     * @return
     */
    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        //登錄不需要校驗(yàn)權(quán)限
        chainDefinition.addPathDefinition("/login", "anon");
        //其他任何url都需要校驗(yàn)是否登錄
        chainDefinition.addPathDefinition("/**", "authc");
        return chainDefinition;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("mySecurityManager") SecurityManager securityManager) {
        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
        filterFactoryBean.setSecurityManager(securityManager);
        filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());
        return filterFactoryBean;
    }

    /**
     * 開(kāi)啟Shiro注解模式,可以在Controller中的方法上添加注解
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("mySecurityManager") SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

這些都是比較固定的代碼,你甚至都不需要知道每個(gè)bean的含義,直接拷貝過(guò)去用,也是沒(méi)有問(wèn)題的。

然后,我們需要自定義一個(gè)Realm。

代碼

package com.it.shirodemo.realm;

import com.it.shirodemo.entity.User;
import com.it.shirodemo.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.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

import javax.annotation.Resource;


public class MyRealm extends AuthorizingRealm {

    @Resource
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 實(shí)現(xiàn)授權(quán)邏輯
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //獲得當(dāng)前subject
        Subject subject = SecurityUtils.getSubject();
        //獲得當(dāng)前的principal,也就是認(rèn)證完后我們放入的信息
        User currentUser = (User) subject.getPrincipal();
        //添加權(quán)限
        info.addStringPermissions(currentUser.getPerms());

        return info;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 實(shí)現(xiàn)認(rèn)證邏輯
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        //從數(shù)據(jù)庫(kù)中查詢?cè)撚脩?
        String username = usernamePasswordToken.getUsername();
        User user = userService.queryUserByName(username);
        //如果不存在該用戶,返回一個(gè)空錯(cuò)誤,前端也可以相應(yīng)顯示提示
        if (user == null) {
            return null;
        }
        // 第一個(gè)參數(shù)為principal,就是授權(quán)方法里面拿到的那個(gè)對(duì)象;
        // 第二個(gè)參數(shù)為從數(shù)據(jù)庫(kù)中查出的用于驗(yàn)證的密碼,shiro中密碼驗(yàn)證不需要我們自己去做;
        // 第三個(gè)參數(shù)為 realmName
        return new SimpleAuthenticationInfo(user,user.getPwd(),getName());
    }
}

主要是寫(xiě)授權(quán)和認(rèn)證的方法,上面的 doGetAuthorizationInfo 用來(lái)授權(quán),在你每一次訪問(wèn)系統(tǒng)的某個(gè)url時(shí)會(huì)調(diào)用,目標(biāo)是獲取當(dāng)前用戶的權(quán)限。

看下用戶類(lèi):

代碼

package com.it.shirodemo.entity;

import lombok.Data;
import java.util.Set;

@Data
public class User {
    private String userName;
    private String pwd;
    private Set<String> perms;
}

perms是一個(gè)Set集合,我們?cè)谀M的service中進(jìn)行初始化和查詢:

package com.it.shirodemo.service;

import com.it.shirodemo.entity.User;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class UserService {


    public User queryUserByName(String username) {
        List<User> users = new ArrayList<>();
        users.add(new User(){{
            setUserName("admin");
            setPwd("123");
            setPerms(new HashSet<String>(){{
                add("shiro:user-query");
                add("shiro:user-add");
                add("shiro:user-delete");
                add("shiro:user-edit");
            }});
        }});

        users.add(new User(){{
            setUserName("zhangsan");
            setPwd("123");
            setPerms(new HashSet<String>(){{
                add("shiro:user-query");
            }});
        }});
        List<User> userList = users.stream().filter(e -> e.getUserName().equals(username)).collect(Collectors.toList());
        if(userList.size() > 0){
            return userList.get(0);
        }
        return null;

    }
}

為了測(cè)試,我們專(zhuān)門(mén)弄了一個(gè)用戶的Controller

package com.it.shirodemo.controller;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1/user/")
public class UserController {

    @GetMapping("/query")
    @RequiresPermissions("shiro:user-query")
    public String query(){
       return "用戶查詢";
    }

    @GetMapping("/edit")
    @RequiresPermissions("shiro:user-edit")
    public String edit(){
        return "用戶修改";
    }

    @GetMapping("/delete")
    @RequiresPermissions("shiro:user-delete")
    public String delete(){
        return "用戶刪除";
    }

    @GetMapping("/add")
    @RequiresPermissions("shiro:user-add")
    public String add(){
        return "用戶新增";
    }
}

我們期望,admin用戶可以訪問(wèn)所有的權(quán)限,zhangsan只能訪問(wèn)用戶查詢的接口。

執(zhí)行完

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    // 實(shí)現(xiàn)授權(quán)邏輯
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //獲得當(dāng)前subject
    Subject subject = SecurityUtils.getSubject();
    //獲得當(dāng)前的principal,也就是認(rèn)證完后我們放入的信息
    User currentUser = (User) subject.getPrincipal();
    //添加權(quán)限
    info.addStringPermissions(currentUser.getPerms());

    return info;
}

這個(gè)授權(quán)方法后,返回的授權(quán)信息對(duì)象就有所有的權(quán)限列表,如果包含了你本次訪問(wèn)的權(quán)限,比如 shiro:user-add ,就允許訪問(wèn),否則不允許訪問(wèn)。

再來(lái)看認(rèn)證方法,認(rèn)證說(shuō)白了就是登錄驗(yàn)證。

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    // 實(shí)現(xiàn)認(rèn)證邏輯
    UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
    //從數(shù)據(jù)庫(kù)中查詢?cè)撚脩?
    String username = usernamePasswordToken.getUsername();
    User user = userService.queryUserByName(username);
    //如果不存在該用戶,返回一個(gè)空錯(cuò)誤,前端也可以相應(yīng)顯示提示
    if (user == null) {
        return null;
    }
    // 第一個(gè)參數(shù)為principal,就是授權(quán)方法里面拿到的那個(gè)對(duì)象;
    // 第二個(gè)參數(shù)為從數(shù)據(jù)庫(kù)中查出的用于驗(yàn)證的密碼,shiro中密碼驗(yàn)證不需要我們自己去做;
    // 第三個(gè)參數(shù)為 realmName
    return new SimpleAuthenticationInfo(user,user.getPwd(),getName());
}

這里有個(gè)很有意思的東西,最終return出去的SimpleAuthenticationInfo對(duì)象,構(gòu)造方法第一個(gè)參數(shù)是一個(gè)Object類(lèi)型。

這個(gè)玩意其實(shí)就是:

也就是說(shuō),你在認(rèn)證方法里面?zhèn)鬟f什么參數(shù),授權(quán)方法里面獲取的principal就是什么對(duì)象。

為什么要提供這么一個(gè)口子讓你傳遞object呢,其實(shí)就是為了讓你在授權(quán)的時(shí)候能獲取當(dāng)前用戶的授權(quán)列表啊!

我看到網(wǎng)上很多講shiro的文章,對(duì)于這一點(diǎn)的理解比較模糊,反正你就記住,這個(gè)參數(shù)你不管傳什么,一定要能夠通過(guò)它來(lái)獲取權(quán)限列表。比如,我這里就傳一個(gè)User對(duì)象,user對(duì)象里面已經(jīng)有perms了,那就沒(méi)問(wèn)題。你也可以傳username,然后在授權(quán)的時(shí)候去數(shù)據(jù)庫(kù)查詢權(quán)限列表,也完全沒(méi)問(wèn)題。

最后,再給出登錄的方法:

package com.it.shirodemo.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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {

    @GetMapping("/login")
    public String login(String username,String password){
        Subject subject = SecurityUtils.getSubject();
        //令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        try {
            //登錄認(rèn)證
            subject.login(token);
            return "恭喜,登錄成功!";
        }catch (UnknownAccountException e){
            return "賬號(hào)不存在";
        }catch (IncorrectCredentialsException e){
            return "密碼錯(cuò)誤";
        }

    }
}

驗(yàn)證,打開(kāi)瀏覽器,因?yàn)槭荊et請(qǐng)求,我們直接用瀏覽器來(lái)發(fā)。

http://localhost:8080/login?username=admin&password=123

然后去訪問(wèn):http://localhost:8080/v1/user/add

如果是張三登錄,訪問(wèn)http://localhost:8080/v1/user/add

后臺(tái)報(bào)錯(cuò)了:

org.apache.shiro.authz.AuthorizationException: Not authorized to invoke method: public java.lang.String com.it.shirodemo.controller.UserController.add()

總結(jié)

本文實(shí)現(xiàn)了所謂ACL的權(quán)限控制,用shiro框架結(jié)合springboot實(shí)現(xiàn),非常適合初學(xué)者學(xué)習(xí)。

源碼下載 https://gitee.com/skyblue0678/shiro-demo

到此這篇關(guān)于springboot結(jié)合shiro實(shí)現(xiàn)身份認(rèn)證的實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)springboot shiro身份認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatis 自帶連接池的具體實(shí)現(xiàn)

    MyBatis 自帶連接池的具體實(shí)現(xiàn)

    MyBatis自帶的PooledDataSource實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)連接池,適合簡(jiǎn)單場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • springboot+mybatis配置clickhouse實(shí)現(xiàn)插入查詢功能

    springboot+mybatis配置clickhouse實(shí)現(xiàn)插入查詢功能

    這篇文章主要介紹了springboot+mybatis配置clickhouse實(shí)現(xiàn)插入查詢功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Java實(shí)現(xiàn)摳圖片文字或簽名的完整代碼

    Java實(shí)現(xiàn)摳圖片文字或簽名的完整代碼

    這篇文章主要介紹了java摳圖片文字或簽名的運(yùn)行原理,本文分步驟通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • Base64與File之間的相互轉(zhuǎn)化方式

    Base64與File之間的相互轉(zhuǎn)化方式

    這篇文章主要介紹了Base64與File之間的相互轉(zhuǎn)化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java為什么占用四個(gè)字節(jié)你知道嗎

    Java為什么占用四個(gè)字節(jié)你知道嗎

    這篇文章主要介紹了Java為什么占四個(gè)字節(jié),文中介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • spring boot自定義log4j2日志文件的實(shí)例講解

    spring boot自定義log4j2日志文件的實(shí)例講解

    下面小編就為大家分享一篇spring boot自定義log4j2日志文件的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • Java程序中Doc文檔注釋示例教程

    Java程序中Doc文檔注釋示例教程

    這篇文章主要為大家介紹了Java程序中Doc文檔注釋的示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2021-10-10
  • java實(shí)現(xiàn)設(shè)置靜態(tài)IP地址和網(wǎng)關(guān)

    java實(shí)現(xiàn)設(shè)置靜態(tài)IP地址和網(wǎng)關(guān)

    在現(xiàn)代企業(yè)網(wǎng)絡(luò)和嵌入式系統(tǒng)中,靜態(tài)?IP?配置的需求非常普遍,本項(xiàng)目旨在使用純?Java的方式,實(shí)現(xiàn)對(duì)指定網(wǎng)卡的靜態(tài)?IP,子網(wǎng)掩碼,網(wǎng)關(guān),DNS等網(wǎng)絡(luò)參數(shù)的配置,需要的可以了解下
    2025-06-06
  • 基于@RequestParam與@RequestBody使用對(duì)比

    基于@RequestParam與@RequestBody使用對(duì)比

    這篇文章主要介紹了@RequestParam與@RequestBody的使用對(duì)比,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • javaweb中Http協(xié)議詳解

    javaweb中Http協(xié)議詳解

    HTTP是hypertext transfer protocol(超文本傳輸協(xié)議)的簡(jiǎn)寫(xiě),它是TCP/IP協(xié)議的一個(gè)應(yīng)用層協(xié)議,用于定義WEB瀏覽器與WEB服務(wù)器之間交換數(shù)據(jù)的過(guò)程。這篇文章主要為大家詳細(xì)介紹了javaweb中的Http協(xié)議,感興趣的小伙伴們可以參考一下
    2016-05-05

最新評(píng)論