shiro登錄密碼驗(yàn)證以及登錄狀態(tài)驗(yàn)證流程

登錄密碼驗(yàn)證流程

1.入口

  • 獲取前端傳過來的用戶信息User
  • 把用戶信息User傳入到實(shí)例對(duì)象UsernamePasswordToken
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","666");
//UsernamePasswordToken 的屬性
// getUsername 賬戶,賬號(hào)
// getPassword 密碼
// getPrincipal 身份 
// getCredentials 加密憑據(jù)
// getHost 主機(jī)地址
// isRememberMe 是否記住賬號(hào)密碼
  • 調(diào)用subject的login方法開始進(jìn)行登錄驗(yàn)證
 Subject subject = SecurityUtils.getSubject();
//此處傳的token是實(shí)例化后的對(duì)象UsernamePasswordToken
 subject.login(token);

2.密碼匹配校驗(yàn)

  • 創(chuàng)建自定義的relam類繼承 AuthorizingRealm 實(shí)現(xiàn)doGetAuthenticationInfo 方法和doGetAuthorizationInfo方法
  • 進(jìn)入到 自定義的relam里的doGetAuthenticationInfo方法里邊進(jìn)行獲取傳過來的用戶信息,然后進(jìn)行密碼匹配,
  • 隨后按照密碼的加密方式選擇密碼匹配器,自定義的話 選擇對(duì)應(yīng)的繼承就好了


    密碼匹配規(guī)則類

doGetAuthorizationInfo

這個(gè)方法主要用來校驗(yàn)用戶的權(quán)限,那什么時(shí)候會(huì)進(jìn)入這個(gè)方法?
  • subject.hasRole(“admin”) 或 subject.isPermitted(“admin”):自己去調(diào)用這個(gè)是否有什么角色或者是否有什么權(quán)限的時(shí)候;
  • @RequiresRoles("admin") :在方法上加注解的時(shí)候;
  • [@shiro.hasPermission name = "admin"][/@shiro.hasPermission]:在頁(yè)面上加shiro標(biāo)簽的時(shí)候,即進(jìn)這個(gè)頁(yè)面的時(shí)候掃描到有這個(gè)標(biāo)簽的時(shí)候
    ------之后生成session

登錄狀態(tài)驗(yàn)證流程

1. 入口

  • 所有的登錄以及未登錄的請(qǐng)求都先進(jìn)入到filter中,按照filter的層級(jí)來進(jìn)行層層校驗(yàn)URL地址
  • isAccessAllowed 所有的接口都會(huì)先進(jìn)入此方法,如果此接口返回true,就判定為已登陸,如果返回false就判定為未登錄 然后進(jìn)入到onAccessDenied方法中 isAccessAllowed 方法的mappedValue 是登錄成功的用戶的權(quán)限信息,可以用來判斷此用戶擁有那些權(quán)限
  • onAccessDenied 判定此用戶未登錄是否可以訪問此頁(yè)面或者接口
package com.eat.config;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @version V1.0
 * @Package com.eat.config
 * @ClassName MyFilter
 * @Description 自定義shiro的過濾器
 * @Author 王振鵬
 * @date 2020/10/26 23:39
 **/
public class MyFilter extends AuthenticatingFilter {

    /**
     * @Summar
     * @Param: [request, response]
     * @Return: org.apache.shiro.authc.AuthenticationToken
     * @Author: TheRaging
     * @Date: 2020/10/26 23:46
     * @Description TODO 創(chuàng)建Token
     */
    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        System.out.println("進(jìn)到了創(chuàng)建TOKEN的方法中");

        return null;
    }

    /**
     * @Summary
     * @Param: [request, response, mappedValue]
     * @Return: boolean
     * @Author: TheRaging
     * @Date: 2020/10/26 23:43
     * @Description 判斷是否登錄,主要用于權(quán)限校驗(yàn),     false的話就代表未登錄,直接進(jìn)入onAccessDenied方法,
     * 如果為true就代表已經(jīng)登錄過,然后直接訪問控制器
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

       /*
        //權(quán)限訪問邏輯
        Subject subject = getSubject(request, response);
        String[] rolesArray = (String[]) mappedValue;
        //沒有權(quán)限訪問
        if (rolesArray == null || rolesArray.length == 0) {
            return true;
        }
        for (int i = 0; i < rolesArray.length; i++) {
            //若當(dāng)前用戶是rolesArray中的任何一個(gè),則有權(quán)限訪問
            if (subject.hasRole(rolesArray[i])) {
                return true;
            }
        }*/
        ShiroHttpServletRequest rrr = (ShiroHttpServletRequest)request;
        String s = rrr.getRequestURI();
        System.out.println(s);
        String token =  getRequestToken((HttpServletRequest)request);
        if(StringUtils.isEmpty(token)){
            //沒有token的話 就去登錄
            System.out.println("tojkren-----------"+token);
            return  false;
        }else {
            //有token的話 選喲解析驗(yàn)證token 驗(yàn)證通過的話就直接權(quán)限校驗(yàn)或者直接訪問,如果校驗(yàn)不通過的話就拒絕登錄
            System.out.println("獲取到了TOKEN-----------"+token);
            return  true;
        }






    }

    /**
     * @Summary
     * @Param: [request, response]
     * @Return: boolean
     * @Author: TheRaging
     * @Date: 2020/10/26 23:44
     * @Description 未登錄狀態(tài)進(jìn)入此方法,
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {



        System.out.println("進(jìn)入到了onAccessDenied方法中");
        return false;
    }

    /**
     * @Summary
     * @Param: [token, e, request, response]
     * @Return: boolean
     * @Author: TheRaging
     * @Date: 2020/10/26 23:46
     * @Description TODO  登錄失敗的一個(gè)處理
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        System.out.println("進(jìn)入到了onLoginFailure方法中");
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setContentType("application/json;charset=utf-8");
        try {
            //處理登錄失敗的異常
            Throwable throwable = e.getCause() == null ? e : e.getCause();
           /* R r = R.error(HttpStatus.SC_UNAUTHORIZED, throwable.getMessage());

            String json = new Gson().toJson(r);
            httpResponse.getWriter().print(json);*/
            httpResponse.getWriter().print("2123");
        } catch (IOException e1) {

        }
        return false;
    }

    /**
     * @Summary
     * @Param: [token, subject, request, response]
     * @Return: boolean
     * @Author: TheRaging
     * @Date: 2020/10/26 23:47
     * @Description TODO  登錄成功的一個(gè)處理
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token,
                                     Subject subject, ServletRequest request, ServletResponse response)
            throws Exception {
        System.out.println("進(jìn)入到了onLoginSuccess方法中");
        Session session = SecurityUtils.getSubject().getSession();
        /*UserInfo user = (UserInfo) subject.getPrincipal();
        session.setAttribute("userName", user.getUserName());
        session.setAttribute("userId", user.getUserId());*/
        issueSuccessRedirect(request, response);
        return false;
    }
    /**
     * 獲取請(qǐng)求的token
     */
    private String getRequestToken(HttpServletRequest httpRequest){
        //從header中獲取token
        String token = httpRequest.getHeader("token");

        //如果header中不存在token,則從參數(shù)中獲取token
        if(StringUtils.isBlank(token)){
            token = httpRequest.getParameter("token");
        }

        return token;
    }
}

shiro的配置文件

package com.eat.config;



import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
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 javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;
/**
 * @version V1.0
 * @Package com.eat.config
 * @ClassName ShiroConfig
 * @Description TODO
 * @Author 王振鵬
 * @date 2020/10/23 22:22
 **/
@Configuration
public class ShiroConfig {

    /**
     * @Summary
     * @Param: []
     * @Return: CustomRealm
     * @Author: TheRaging
     * @Date: 2020/10/23 22:28
     * @Description 配置ShiroRealm用于登錄驗(yàn)證邏輯,返回自定義的ShiroRealm 相當(dāng)于一個(gè)數(shù)據(jù)源
     * 身份驗(yàn)證(getAuthenticationInfo 方法)驗(yàn)證賬戶和密碼,并返回相關(guān)信息
     * 權(quán)限獲?。╣etAuthorizationInfo 方法) 獲取指定身份的權(quán)限,并返回相關(guān)信息
     * 令牌支持(supports方法)判斷該令牌(Token)是否被支持
     */
    @Bean
    public MyRealm myShiroRealm() {
        MyRealm customRealm = new MyRealm();
        //自定義密碼驗(yàn)證
        customRealm.setCredentialsMatcher(myCredentialsMatcher());
        return customRealm;
    }

    /**
     * @Summary
     * @Param: []
     * @Return: java.lang.SecurityManager
     * @Author: TheRaging
     * @Date: 2020/10/23 22:29
     * @Description 配置SecurityManager,用于管理認(rèn)證
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        //設(shè)置自定義的session管理器
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * @Summary
     * @Param: [securityManager]
     * @Return: ShiroFilterFactoryBean
     * @Author: TheRaging
     * @Date: 2020/10/23 22:30
     * @Description 配置ShiroFilterFactoryBean過濾器,用于過濾url地址,然后決定哪些路徑需要認(rèn)證
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //設(shè)置使用自定義的filter進(jìn)行過濾
        Map<String, Filter> filters = new HashMap<>();
        filters.put("filter", new MyFilter());
        //配置自定義的過濾規(guī)則
        shiroFilterFactoryBean.setFilters(filters);
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String, String> map = new HashMap<>();
        //登錄
        map.put("/test/login", "anon");
        //登出
        map.put("/logout", "logout");
        //登錄失敗跳轉(zhuǎn)的頁(yè)面
       // shiroFilterFactoryBean.setLoginUrl("/test/login");
        //配置登錄成功的跳轉(zhuǎn)頁(yè)面,默認(rèn)跳轉(zhuǎn)到/
        //shiroFilterFactoryBean.setSuccessUrl("/index");
        //沒有權(quán)限,權(quán)限校驗(yàn)失敗跳轉(zhuǎn)的頁(yè)面
        //shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        //對(duì)所有用戶認(rèn)證
        map.put("/**", "filter");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    /**
     * shiro緩存管理器
     * 1 添加相關(guān)的maven支持
     * 2 注冊(cè)這個(gè)bean,將緩存的配置文件導(dǎo)入
     * 3 在securityManager 中注冊(cè)緩存管理器,之后就不會(huì)每次都會(huì)去查詢數(shù)據(jù)庫(kù)了,相關(guān)的權(quán)限和角色會(huì)保存在緩存中,但需要注意一點(diǎn),更新了權(quán)限等操作之后,需要及時(shí)的清理緩存
     */
   /* @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager cacheManager = new EhCacheManager();
        cacheManager.setCacheManagerConfigFile("classpath:config/ehcache.xml");
        return cacheManager;
    }*/


    /**
     * 自定義的 shiro session 緩存管理器,用于跨域等情況下使用 token 進(jìn)行驗(yàn)證,不依賴于sessionId
     * @return
     */
    @Bean
    public SessionManager sessionManager(){
        //將我們繼承后重寫的shiro session 注冊(cè)
        MySession shiroSession = new MySession();
        //如果后續(xù)考慮多tomcat部署應(yīng)用,可以使用shiro-redis開源插件來做session 的控制,或者nginx 的負(fù)載均衡
        shiroSession.setSessionDAO(new EnterpriseCacheSessionDAO());
        return shiroSession;
    }

    /**
     * @Summary
     * @Param: []
     * @Return: MyCredentialsMatcher
     * @Author: TheRaging
     * @Date: 2020/10/23 23:45
     * @Description 配置自定義的密碼校驗(yàn)類MyCredentialsMatcher
     * MyCredentialsMatcher 需要繼承CredentialsMatcher 實(shí)現(xiàn)重寫
     * 但是同時(shí)需要在SecurityManager中設(shè)置
     * SecurityManager.setCredentialsMatcher(myCredentialsMatcher());
     */
    @Bean
    public MyCredentialsMatcher myCredentialsMatcher() {
        return new MyCredentialsMatcher();
    }


    /**
     * @Summary
     * @Param: []
     * @Return: org.apache.shiro.mgt.SecurityManager
     * @Author: TheRaging
     * @Date: 2020/10/23 23:51
     * @Description 配置實(shí)現(xiàn)自定義的securityManager
     * MySessionManager需要繼承 DefaultWebSessionManager 實(shí)現(xiàn)重寫
     * 但是同時(shí)也需要在 securityManager 中添加
     * SecurityManager.setSessionManager(sessionManager());
     */
  /*  @Bean
    public SessionManager sessionManager(){
        MySessionManager mySessionManager = new MySessionManager();
        //這里可以不設(shè)置。Shiro有默認(rèn)的session管理。如果緩存為Redis則需改用Redis的管理
        mySessionManager.setSessionDAO(new EnterpriseCacheSessionDAO());
        return mySessionManager;
    }*/



    //DefaultAdvisorAutoProxyCreator 和AuthorizationAttributeSourceAdvisor兩個(gè)在一起才能支Shiro的注解權(quán)限控制實(shí)現(xiàn)
    /**
     * @Summary
     * @Param: []
     * @Return: org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
     * @Author: TheRaging
     * @Date: 2020/10/23 22:33
     * @Description  配置,這個(gè)是AOP的,相當(dāng)于一個(gè)切面
     *  他會(huì)掃描所有的類中的Advisor,
     *  然后這些Advisor應(yīng)用到所有符合切入點(diǎn)的Bean中
     */
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    /**
     * @Summary
     * @Param: [securityManager]
     * @Return: AuthorizationAttributeSourceAdvisor
     * @Author: TheRaging
     * @Date: 2020/10/23 22:38
     * @Description 配置 aop  這個(gè)類就相當(dāng)于切點(diǎn)了
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容