一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - springboot下使用shiro自定義filter的個人經驗分享

springboot下使用shiro自定義filter的個人經驗分享

2022-01-06 12:16追逐夢想永不停 Java教程

這篇文章主要介紹了springboot下使用shiro自定義filter的個人經驗,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

在springboot中使用shiro,由于沒有了xml配置文件,因此使用的方法與spring中有些區別。在踩了無數個坑后,在此將springboot下使用shiro的步驟總結如下。

由于本人對shiro的了解不是很深入,在實現了工作需求后就沒有繼續研究了,因此可能存在遺漏的地方或有錯誤的地方,還請多包涵。

目標

  • 在springboot中使用shiro
  • 1.實現用戶的登錄驗證
  • 2.對于一些指定的url使用自定義的filter驗證方式(不再使用shiro的realm驗證)

步驟

1.在pom.xml中添加shiro的依賴

?
1
2
3
4
5
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.3.2</version>
</dependency>

2.創建ShiroRealm.java

繼承AuthorizingRealm類,重寫登錄認證方法與授權方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import User;
import UserService;
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.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
 
public class ShiroRealm extends AuthorizingRealm {
    //自己編寫的service,注入,執行數據庫查詢方法用
    @Autowired
    private UserService userService;
    //認證.登錄
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken utoken=(UsernamePasswordToken) token;//獲取用戶輸入的token
        String username = utoken.getUsername();
        //這個User對象為自定義的JavaBean,使用userService從數據庫中得到User對象(包含用戶名、密碼、權限3個字段)
        User user = userService.findUserByUserName(username);
        return new SimpleAuthenticationInfo(user, user.getPassword(),this.getClass().getName());//放入shiro.調用CredentialsMatcher檢驗密碼
    }
    //授權
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        User user=(User) principal.fromRealm(this.getClass().getName()).iterator().next();//獲取session中的用戶
        List<String> permissions=new ArrayList<>();
        //使用自定義的user對象獲得權限字段,string類型,裝入集合
        permissions.add(user.getRole());
 
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        info.addStringPermissions(permissions);//將權限放入shiro中.(我的代碼中其實沒有用到權限相關)
        return info;
    }
}

3.創建ShiroConfiguration.java

使用@Configuration注解,是shiro的配置類,類似xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.mgt.SecurityManager;
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 javax.servlet.Filter;
 
@Configuration
public class ShiroConfiguration {
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();
        // 必須設置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
 
        /*重要,設置自定義攔截器,當訪問某些自定義url時,使用這個filter進行驗證*/
        Map<String, Filter> filters = new LinkedHashMap<String, Filter>();
        //如果map里面key值為authc,表示所有名為authc的過濾條件使用這個自定義的filter
        //map里面key值為myFilter,表示所有名為myFilter的過濾條件使用這個自定義的filter,具體見下方
        filters.put("myFilter", new MyFilter());
        shiroFilterFactoryBean.setFilters(filters);
        /*---------------------------------------------------*/
 
        //攔截器
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        //配置退出過濾器,其中的具體的退出代碼Shiro已經替我們實現了
        filterChainDefinitionMap.put("/logout", "logout");
        //  anon:所有url都都可以匿名訪問;
        //  authc: 需要認證才能進行訪問;
        //  user:配置記住我或認證通過可以訪問;
        //放開靜態資源的過濾
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        //放開登錄url的過濾
        filterChainDefinitionMap.put("/loginController", "anon");
        ///
        //對于指定的url,使用自定義filter進行驗證
        filterChainDefinitionMap.put("/targetUrl", "myFilter");
        //可以配置多個filter,用逗號分隔,按順序過濾,下方表示先通過自定義filter的驗證,再通過shiro默認過濾器的驗證
        //filterChainDefinitionMap.put("/targetUrl", "myFilter,authc");
        ///
        //過濾鏈定義,從上向下順序執行,一般將 /**放在最為下邊
        //url從上向下匹配,當條件匹配成功時,就會進入指定filter并return(不會判斷后續的條件),因此這句需要在最下邊
        filterChainDefinitionMap.put("/**", "authc");
 
        //如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登錄成功后要跳轉的鏈接
        shiroFilterFactoryBean.setSuccessUrl("/loginSuccess");
        // 未授權界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
 
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        return securityManager;
    }
    //配置核心安全事務管理器
    @Bean(name="securityManager")
    public SecurityManager securityManager(@Qualifier("shiroRealm") ShiroRealm shiroRealm) {
        DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
        manager.setRealm(shiroRealm);
        return manager;
    }
    //配置自定義的權限登錄器
    @Bean(name="shiroRealm")
    public ShiroRealm shiroRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
        ShiroRealm shiroRealm=new ShiroRealm();
        shiroRealm.setCredentialsMatcher(matcher);
        return shiroRealm;
    }
    //配置自定義的密碼比較器
    @Bean(name="credentialsMatcher")
    public CredentialsMatcher credentialsMatcher() {
        return new CredentialsMatcher();
    }
}

4.創建自定義的過濾器MyFilter.java

繼承AccessControlFilter類,在步驟3中使用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Set;
public class MyFilter extends AccessControlFilter {
    private static Logger log = LoggerFactory.getLogger(MyFilter.class);
 
    //判斷是否攔截,false為攔截,true為允許
    @Override
    public boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object object) throws Exception {
        Subject subject = getSubject(req,resp);
        String url = getPathWithinApplication(req);
        log.info("當前用戶正在訪問的url為 " + url);
        log.info("subject.isPermitted(url);"+subject.isPermitted(url));
        //可自行根據需要判斷是否攔截,可以獲得subject判斷用戶權限,也可以使用req獲得請求頭請求體信息
        //return true;
        return false;       
    }
 
    //上面的方法返回false后(被攔截),會進入這個方法;這個方法返回false表示處理完畢(不放行);返回true表示需要繼續處理(放行)
    @Override
    public boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {    
        //從req中獲得的值,也可以自己使用其它判斷是否放行的方法
        String username = request.getParameter("name");
        String password = request.getParameter("password");
        //創建token對象
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
        Subject subject = SecurityUtils.getSubject();
        try {
            //使用subject對象的login方法驗證該token能否登錄(使用方法2中的shiroRealm.java中的方法驗證)
            subject.login(usernamePasswordToken);
        } catch (Exception e) {
            //log.info("登陸失敗");
            //log.info(e.getMessage());
            return false;
        }
        //log.info("登陸成功");
        return true;
    }
}

5.步驟3中使用了自定義密碼驗證的方式

因此需要創建類CredentialsMatcher.java(與步驟3中的名稱對應),繼承SimpleCredentialsMatcher類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;
public class CredentialsMatcher extends SimpleCredentialsMatcher {
 
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        UsernamePasswordToken utoken=(UsernamePasswordToken) token;
        //獲得用戶輸入的密碼:(可以采用加鹽(salt)的方式去檢驗)
        String inPassword = new String(utoken.getPassword());
        //獲得數據庫中的密碼
        String dbPassword=(String) info.getCredentials();
        //進行密碼的比對
        return this.equals(inPassword, dbPassword);
    }
}

6.步驟3中放開了對登錄頁/loginController的過濾

因此我增加了一個ShiroController.java類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
 
@Controller
public class ShiroController {
    @RequestMapping("/")
    public String loginPage() {
        return "login";
    }
    @RequestMapping("/login")
    public String login() {
        return "login";
    }
    @RequestMapping("/loginController")
    public String loginUser(String username,String password,HttpSession session) {
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(username,password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(usernamePasswordToken);   //完成登錄
            //自定義的JavaBean,用于保存用戶名、密碼、權限3個字段
            User user=(User) subject.getPrincipal();
            //可選,可放入session,以備后續使用
            session.setAttribute("user", user);
            //跳轉到登錄成功頁(controller)
            return "forward:/loginSuccess";
        } catch(Exception e) {
            //登錄失敗,跳轉回登錄頁(html)
            return "login";
        }
    }
    @RequestMapping("/logOut")
    public String logOut(HttpSession session) {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        //session.removeAttribute("user");
        return "login";
    }
}

個人經驗

1.shiro配置類中的url攔截的執行順序為從上到下,如果url匹配到一個規則,則會跳出匹配方法,忽略后續的匹配規則(相當于return)。

2.shiro使用自定義filter時,最好繼承shiro的filter,不要直接繼承Filter類。

3.shiro使用自定義filter時,map集合的key配置為"authc"、value配置為"new MyFilter()"時,表示對配置為authc的url使用自定義filter進行攔截,而不會使用ShiroRealm中的驗證方法驗證(可能是將shiro默認的authc的攔截器覆蓋了);因此最好將key配置為其它自定義的字符串,將部分url的攔截規則設置為使用自定義filter攔截即可(如果仍想使用shiro默認的攔截器,可用逗號連接"authc")。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/BHSZZY/article/details/85328353

延伸 · 閱讀

精彩推薦
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
主站蜘蛛池模板: 国产东北三老头伦一肥婆 | daring国家队在线观看樱花动漫 | 男人把大ji巴放进男人免费视频 | 四虎永久免费地址在线网站 | 国产精品亚洲午夜一区二区三区 | 欧美一区二区三区四区五区六区 | 亚洲天天综合网 | 久久精品WWW人人爽人人 | 91欧美秘密入口 | 色综合久久九月婷婷色综合 | 波多野结衣女老师 | 九九热精品免费观看 | 欧美日韩综合一区 | 精品免费国产一区二区三区 | 日剧整部剧护妻狂魔免费观看全集 | 超大阿力gaysex | 四虎免费影院在线播放 | 都市后宫小说 | 男人在线影院 | 51精品 | 晓雪老师我要进你里面好爽 | 国产偷窥女洗浴在线观看亚洲 | 日本捏胸吃奶视频免费 | 国产香蕉97碰碰在线视频 | 午夜一个人在线观看完整版 | 日本综合在线观看 | 欧美日韩一二三区免费视频观看 | 黄动漫车车好快的车车a | 日本午夜影院 | 电车痴汉中文字幕 | 亚洲精品久久久久久婷婷 | 午夜桃色剧场 | 国产在线观看福利 | 日本午夜vr影院新入口 | 扒开老师挠尿口到崩溃刑罚 | 午夜神器18以下不能进免费 | 欧美伊香蕉久久综合类网站 | 91久久碰国产 | 1769最新资源站 | 天天综合天天色 | 亚洲四虎在线 |