spring boot + shiro 整合報錯:Authentication failed for token submission [org.apache.shiro.authc.UsernamePasswordToken - admin, rememberMe=false]


今天在做springboot和shiro整合練習的時候出現了一個錯誤,希望對初學者遇到同樣問題有所幫助

1、錯誤信息

2019-10-29 11:39:06.809  WARN 14068 --- [nio-8081-exec-1] o.a.shiro.authc.AbstractAuthenticator    : Authentication failed for token submission [org.apache.shiro.authc.UsernamePasswordToken - admin, rememberMe=false].  Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException).

java.lang.NullPointerException: null
    at com.example.shiro.config.CustomRealm.doGetAuthenticationInfo(CustomRealm.java:60) ~[classes/:na]
    at org.apache.shiro.realm.AuthenticatingRealm.getAuthenticationInfo(AuthenticatingRealm.java:571) ~[shiro-core-1.4.1.jar:1.4.1]
    at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(ModularRealmAuthenticator.java:180) ~[shiro-core-1.4.1.jar:1.4.1]
    at org.apache.shiro.authc.pam.ModularRealmAuthenticator.doAuthenticate(ModularRealmAuthenticator.java:267) ~[shiro-core-1.4.1.jar:1.4.1]
    at org.apache.shiro.authc.AbstractAuthenticator.authenticate(AbstractAuthenticator.java:198) ~[shiro-core-1.4.1.jar:1.4.1]
    at org.apache.shiro.mgt.AuthenticatingSecurityManager.authenticate(AuthenticatingSecurityManager.java:106) [shiro-core-1.4.1.jar:1.4.1]
    at org.apache.shiro.mgt.DefaultSecurityManager.login(DefaultSecurityManager.java:275) [shiro-core-1.4.1.jar:1.4.1]
    at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:260) [shiro-core-1.4.1.jar:1.4.1]
    at com.example.shiro.controller.UserController.login(UserController.java:32) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_211]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_211]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_211]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_211]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) [spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) [spring-web-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) [tomcat-embed-core-9.0.27.jar:9.0.27]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) [spring-webmvc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.27.jar:9.0.27]

上面出現的NPE , at com.example.shiro.config.CustomRealm.doGetAuthenticationInfo(CustomRealm.java:60) ~[classes/:na] 是String password = userService.getPasswordByUsername(userName); 這行代碼

2、realm源代碼

public class CustomRealm extends AuthorizingRealm {
    @Autowired
    private RoleService roleService;
    @Autowired
    private RolePermissionService rolePermissionService;
    @Autowired
    private UserService userService;

 //認證
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //從主體傳過來的認證信息中,獲取用戶名
        String userName = (String)authenticationToken.getPrincipal();

        //通過用戶名去到數據庫中獲取憑證
        String password = userService.getPasswordByUsername(userName);
        if (StringUtils.isEmpty(password)) {
            return null;
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userName, password, "costomRealm");
        //設置鹽salt
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("pyy"));

        return simpleAuthenticationInfo;
    }
}

3、shiro配置類代碼

 @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        CustomRealm customRealm = new CustomRealm();

        //加密配置
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //設置加密算法名稱
        matcher.setHashAlgorithmName("md5");
        //設置加密次數
        matcher.setHashIterations(1);
        customRealm.setCredentialsMatcher(matcher);

        //設置Realm
        securityManager.setRealm(customRealm);

        return securityManager;
    }

4、debug時的現象

 

報NPE, 說明userService沒有注入進來,為什么?

因為shiro 的realm本身相當於過濾器,而在登錄訪問時會先走過濾器,再執行service注入,這就會出現還沒有進行service注入,已經再realm中調用注入的對象,所以就會出現上述現象

解決辦法:

  將realm已bean的形式生成,那么再生成時就會強制注入service對象,這樣就避免了上述問題,具體代碼如下, 

 @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //設置Realm
        securityManager.setRealm(customRealm());

        return securityManager;
    }

    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();

        //加密配置
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //設置加密算法名稱
        matcher.setHashAlgorithmName("md5");
        //設置加密次數
        matcher.setHashIterations(1);
        customRealm.setCredentialsMatcher(matcher);

        return customRealm;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM