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

SecurityUtils.getSubject().getPrincipal()為null的問題

 更新時(shí)間:2022年07月01日 09:56:17   作者:神雕大俠mu  
這篇文章主要介紹了SecurityUtils.getSubject().getPrincipal()為null的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

SecurityUtils.getSubject().getPrincipal()為null

我在項(xiàng)目中獲取getUserId(),和getUserName()獲取不到值。

他們都是通過SecurityUtils.getSubject().getPrincipal()去獲取的。

反復(fù)測試發(fā)現(xiàn)原因是 :在shiroConfig里面:

該方法,注意(是該接口名)被寫為anon,不通過驗(yàn)證,即:

filterMap.put("/druid/**", “anon”);

這種寫法是為了postman測試時(shí)不被攔截。

解決辦法

從頁面訪問后端不需要anon了。

  • anon是不做攔截,authc是走自定義攔截
  • oauth2是自帶攔截

修改為:

filterMap.put("/druid/**", “authc”);

shiro SecurityUtils.getSubject()深度分析

1.總的來說,SecurityUtils.getSubject()是每個(gè)請求創(chuàng)建一個(gè)Subject, 并保存到ThreadContext的resources(ThreadLocal<Map<Object, Object>>)變量中,也就是一個(gè)http請求一個(gè)subject,并綁定到當(dāng)前過程。 

問題來了:.subject.login()登陸認(rèn)證成功后,下一次請求如何知道是那個(gè)用戶的請求呢? 

友情提示:本文唯一可以讀一下的就是分析這個(gè)疑問,如果你已經(jīng)明白就不用往下看了。 

首先給出內(nèi)部原理:1個(gè)請求1個(gè)Subject原理:由于ShiroFilterFactoryBean本質(zhì)是個(gè)AbstractShiroFilter過濾器,所以每次請求都會(huì)執(zhí)行doFilterInternal里面的createSubject方法。 

猜想:因?yàn)閟ubject是綁定到當(dāng)前線程,這肯定需要一個(gè)中介存儲(chǔ)狀態(tài) 

public static Subject getSubject() {  
    Subject subject = ThreadContext.getSubject();  
    if (subject == null) {  
        subject = (new Builder()).buildSubject();  
        ThreadContext.bind(subject);  
    }  
    return subject;  
}  
public abstract class ThreadContext {  
    private static final Logger log = LoggerFactory.getLogger(ThreadContext.class);  
    public static final String SECURITY_MANAGER_KEY = ThreadContext.class.getName() + "_SECURITY_MANAGER_KEY";  
    public static final String SUBJECT_KEY = ThreadContext.class.getName() + "_SUBJECT_KEY";  
    private static final ThreadLocal<Map<Object, Object>> resources = new ThreadContext.InheritableThreadLocalMap();  
  
    protected ThreadContext() {  
    }  
  
    public static Map<Object, Object> getResources() {  
        return (Map)(resources.get() == null ? Collections.emptyMap() : new HashMap((Map)resources.get()));  
    }  
  
    public static void setResources(Map<Object, Object> newResources) {  
        if (!CollectionUtils.isEmpty(newResources)) {  
            ensureResourcesInitialized();  
            ((Map)resources.get()).clear();  
            ((Map)resources.get()).putAll(newResources);  
        }  
    }  
  
    private static Object getValue(Object key) {  
        Map<Object, Object> perThreadResources = (Map)resources.get();  
        return perThreadResources != null ? perThreadResources.get(key) : null;  
    }  
  
    private static void ensureResourcesInitialized() {  
        if (resources.get() == null) {  
            resources.set(new HashMap());  
        }  
  
    }  
  
    public static Object get(Object key) {  
        if (log.isTraceEnabled()) {  
            String msg = "get() - in thread [" + Thread.currentThread().getName() + "]";  
            log.trace(msg);  
        }  
  
        Object value = getValue(key);  
        if (value != null && log.isTraceEnabled()) {  
            String msg = "Retrieved value of type [" + value.getClass().getName() + "] for key [" + key + "] bound to thread [" + Thread.currentThread().getName() + "]";  
            log.trace(msg);  
        }  
  
        return value;  
    }  
  
    public static void put(Object key, Object value) {  
        if (key == null) {  
            throw new IllegalArgumentException("key cannot be null");  
        } else if (value == null) {  
            remove(key);  
        } else {  
            ensureResourcesInitialized();  
            ((Map)resources.get()).put(key, value);  
            if (log.isTraceEnabled()) {  
                String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" + key + "] to thread [" + Thread.currentThread().getName() + "]";  
                log.trace(msg);  
            }  
  
        }  
    }  
  
    public static Object remove(Object key) {  
        Map<Object, Object> perThreadResources = (Map)resources.get();  
        Object value = perThreadResources != null ? perThreadResources.remove(key) : null;  
        if (value != null && log.isTraceEnabled()) {  
            String msg = "Removed value of type [" + value.getClass().getName() + "] for key [" + key + "]from thread [" + Thread.currentThread().getName() + "]";  
            log.trace(msg);  
        }  
  
        return value;  
    }  
  
    public static void remove() {  
        resources.remove();  
    }  
  
    public static SecurityManager getSecurityManager() {  
        return (SecurityManager)get(SECURITY_MANAGER_KEY);  
    }  
  
    public static void bind(SecurityManager securityManager) {  
        if (securityManager != null) {  
            put(SECURITY_MANAGER_KEY, securityManager);  
        }  
  
    }  
  
    public static SecurityManager unbindSecurityManager() {  
        return (SecurityManager)remove(SECURITY_MANAGER_KEY);  
    }  
  
    public static Subject getSubject() {  
        return (Subject)get(SUBJECT_KEY);  
    }  
  
    public static void bind(Subject subject) {  
        if (subject != null) {  
            put(SUBJECT_KEY, subject);  
        }  
  
    }  
  
    public static Subject unbindSubject() {  
        return (Subject)remove(SUBJECT_KEY);  
    }  
  
    private static final class InheritableThreadLocalMap<T extends Map<Object, Object>> extends InheritableThreadLocal<Map<Object, Object>> {  
        private InheritableThreadLocalMap() {  
        }  
  
        protected Map<Object, Object> childValue(Map<Object, Object> parentValue) {  
            return parentValue != null ? (Map)((HashMap)parentValue).clone() : null;  
        }  
    }  
}  

subject登陸成功后,下一次請求如何知道是那個(gè)用戶的請求呢? 

經(jīng)過源碼分析,核心實(shí)現(xiàn)如下DefaultSecurityManager類中: 

public Subject createSubject(SubjectContext subjectContext) {  
    SubjectContext context = this.copy(subjectContext);  
    context = this.ensureSecurityManager(context);  
    context = this.resolveSession(context);  
    context = this.resolvePrincipals(context);  
    Subject subject = this.doCreateSubject(context);  
    this.save(subject);  
    return subject;  
}  

每次請求都會(huì)重新設(shè)置Session和Principals,看到這里大概就能猜到:如果是web工程,直接從web容器獲取httpSession,然后再從httpSession獲取Principals,本質(zhì)就是從cookie獲取用戶信息,然后每次都設(shè)置Principal,這樣就知道是哪個(gè)用戶的請求,并只得到這個(gè)用戶有沒有人認(rèn)證成功,--本質(zhì):依賴于瀏覽器的cookie來維護(hù)session的 

擴(kuò)展,如果不是web容器的app,如何實(shí)現(xiàn)實(shí)現(xiàn)無狀態(tài)的會(huì)話 

1.一般的作法會(huì)在header中帶有一個(gè)token,或者是在參數(shù)中,后臺(tái)根據(jù)這個(gè)token來進(jìn)行校驗(yàn)這個(gè)用戶的身份,但是這個(gè)時(shí)候,servlet中的session就無法保存,我們在這個(gè)時(shí)候,就要實(shí)現(xiàn)自己的會(huì)話創(chuàng)建,普通的作法就是重寫session與request的接口,然后在過濾器在把它替換成自己的request,所以得到的session也是自己的session,然后根據(jù)token來創(chuàng)建和維護(hù)會(huì)話 

2.shiro實(shí)現(xiàn): 

重寫shiro的sessionManage 

import org.apache.shiro.session.mgt.SessionKey;  
import org.apache.shiro.web.servlet.ShiroHttpServletRequest;  
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;  
import org.apache.shiro.web.util.WebUtils;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import java.io.Serializable;  
import java.util.UUID;  
  
/** 
 * @author zxj<br> 
 * 時(shí)間 2017/11/8 15:55 
 * 說明 ... 
 */  
public class StatelessSessionManager extends DefaultWebSessionManager {  
    /** 
     * 這個(gè)是服務(wù)端要返回給客戶端, 
     */  
    public final static String TOKEN_NAME = "TOKEN";  
    /** 
     * 這個(gè)是客戶端請求給服務(wù)端帶的header 
     */  
    public final static String HEADER_TOKEN_NAME = "token";  
    public final static Logger LOG =         LoggerFactory.getLogger(StatelessSessionManager.class);  
  
    @Override  
    public Serializable getSessionId(SessionKey key) {  
        Serializable sessionId = key.getSessionId();  
        if(sessionId == null){  
            HttpServletRequest request = WebUtils.getHttpRequest(key);  
            HttpServletResponse response = WebUtils.getHttpResponse(key);  
            sessionId = this.getSessionId(request,response);  
        }  
        HttpServletRequest request = WebUtils.getHttpRequest(key);  
        request.setAttribute(TOKEN_NAME,sessionId.toString());  
        return sessionId;  
    }  
  
    @Override  
    protected Serializable getSessionId(ServletRequest servletRequest, ServletResponse servletResponse) {  
        HttpServletRequest request = (HttpServletRequest) servletRequest;  
        String token = request.getHeader(HEADER_TOKEN_NAME);  
        if(token == null){  
            token = UUID.randomUUID().toString();  
        }  
  
        //這段代碼還沒有去查看其作用,但是這是其父類中所擁有的代碼,重寫完后我復(fù)制了過來...開始  
        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,  
                ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);  
        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, token);  
        request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);  
        request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, isSessionIdUrlRewritingEnabled());  
        //這段代碼還沒有去查看其作用,但是這是其父類中所擁有的代碼,重寫完后我復(fù)制了過來...結(jié)束  
        return token;  
    }
}
 
    @RequestMapping("/")  
    public void login(@RequestParam("code")String code, HttpServletRequest request){  
        Map<String,Object> data = new HashMap<>();  
        if(SecurityUtils.getSubject().isAuthenticated()){  
        //這里代碼著已經(jīng)登陸成功,所以自然不用再次認(rèn)證,直接從rquest中取出就行了,  
            data.put(StatelessSessionManager.HEADER_TOKEN_NAME,getServerToken());  
            data.put(BIND,ShiroKit.getUser().getTel() != null);  
            response(data);  
        }  
        LOG.info("授權(quán)碼為:" + code);  
        AuthorizationService authorizationService = authorizationFactory.getAuthorizationService(Constant.clientType);  
        UserDetail authorization = authorizationService.authorization(code);  
  
        Oauth2UserDetail userDetail = (Oauth2UserDetail) authorization;  
  
        loginService.login(userDetail);  
        User user = userService.saveUser(userDetail,Constant.clientType.toString());  
        ShiroKit.getSession().setAttribute(ShiroKit.USER_DETAIL_KEY,userDetail);  
        ShiroKit.getSession().setAttribute(ShiroKit.USER_KEY,user);  
        data.put(BIND,user.getTel() != null);  
    //這里的代碼,必須放到login之執(zhí)行,因?yàn)閘ogin后,才會(huì)創(chuàng)建session,才會(huì)得到最新的token咯  
        data.put(StatelessSessionManager.HEADER_TOKEN_NAME,getServerToken());  
        response(data);  
    }
}
import org.apache.shiro.mgt.SecurityManager;  
import org.apache.shiro.realm.Realm;  
import org.apache.shiro.spring.LifecycleBeanPostProcessor;  
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;  
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
  
import java.util.LinkedHashMap;  
import java.util.Map;  
  
/** 
 * @author zxj<br> 
 * 時(shí)間 2017/11/8 15:40 
 * 說明 ... 
 */  
@Configuration  
public class ShiroConfiguration {  
  
    @Bean  
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){  
        return new LifecycleBeanPostProcessor();  
    }  
  
    /** 
     * 此處注入一個(gè)realm 
     * @param realm 
     * @return 
     */  
    @Bean  
    public SecurityManager securityManager(Realm realm){  
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();  
        securityManager.setSessionManager(new StatelessSessionManager());  
        securityManager.setRealm(realm);  
        return securityManager;  
    }  
  
    @Bean  
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){  
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();  
        bean.setSecurityManager(securityManager);  
  
        Map<String,String> map = new LinkedHashMap<>();  
        map.put("/public/**","anon");  
        map.put("/login/**","anon");  
        map.put("/**","user");  
        bean.setFilterChainDefinitionMap(map);    
        return bean;  
    }  
}  

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。 

相關(guān)文章

  • java 使用foreach遍歷集合元素的實(shí)例

    java 使用foreach遍歷集合元素的實(shí)例

    這篇文章主要介紹了java 使用foreach遍歷集合元素的實(shí)例的相關(guān)資料,這里提供實(shí)例幫助大家理解如何使用foreach 進(jìn)行遍歷,希望能幫助到大家,
    2017-08-08
  • SpringMVC跨服務(wù)器上傳文件中出現(xiàn)405錯(cuò)誤的解決

    SpringMVC跨服務(wù)器上傳文件中出現(xiàn)405錯(cuò)誤的解決

    這篇文章主要介紹了SpringMVC跨服務(wù)器上傳文件中出現(xiàn)405錯(cuò)誤的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • springmvc+maven搭建web項(xiàng)目

    springmvc+maven搭建web項(xiàng)目

    這篇文章主要為大家詳細(xì)介紹了springmvc+maven搭建web項(xiàng)目的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • SWT(JFace) 簡易瀏覽器 制作實(shí)現(xiàn)代碼

    SWT(JFace) 簡易瀏覽器 制作實(shí)現(xiàn)代碼

    SWT(JFace) 簡易瀏覽器 制作實(shí)現(xiàn)代碼
    2009-06-06
  • java枚舉類型-Enum

    java枚舉類型-Enum

    本文詳細(xì)介紹了 Java1.5 引入的新特性枚舉中的關(guān)鍵字enum,運(yùn)用大量的代碼加以解釋,相信可以幫助到正在學(xué)習(xí)該知識(shí)的小伙伴,大家可以參考一下
    2021-08-08
  • 探討:如何在NDK中呼叫Java的class

    探討:如何在NDK中呼叫Java的class

    本篇文章是對如何在NDK中呼叫Java的class進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • PowerJob的Evaluator方法工作流程源碼解讀

    PowerJob的Evaluator方法工作流程源碼解讀

    這篇文章主要介紹了PowerJob的Evaluator方法工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • springboot prototype設(shè)置多例不起作用的解決操作

    springboot prototype設(shè)置多例不起作用的解決操作

    這篇文章主要介紹了springboot prototype設(shè)置多例不起作用的解決操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 手工搭建Servlet實(shí)現(xiàn)

    手工搭建Servlet實(shí)現(xiàn)

    現(xiàn)在作為一個(gè)Java程序員,我們已經(jīng)習(xí)慣了使用IDE和Web框架進(jìn)行開發(fā),IDE幫助我們做了編譯、打包的工作。Spring框架則幫助我們實(shí)現(xiàn)了Servlet接口,并把Servlet容器注冊到了Web容器中。本文主要介紹了Servlet手工搭建,感興趣的可以了解一下
    2021-07-07
  • java9的JShell小工具和編譯器兩種自動(dòng)優(yōu)化方法

    java9的JShell小工具和編譯器兩種自動(dòng)優(yōu)化方法

    這篇文章主要介紹了java9的JShell小工具和編譯器兩種自動(dòng)優(yōu)化方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07

最新評論