Spring Security UserDetailsService 抛出 UsernameNotFoundException
在Spring Security中,它们会自动将输入的用户名和密码与数据库保存的用户名和密码进行匹配。当密码不匹配时,它会返回错误的凭据。但是,在我的代码中,只要我知道,如果用户名也不与数据库保存的用户名匹配,它们应该返回错误的凭据。但是,在我的代码中,仅当用户名正确且密码错误时才会显示错误的凭据,并且当用户名不在数据库中时,它会抛出 usernmaenotfoundException。
我知道我在 loaduserByusername 中写了 usernamenotfoundexception。但是,是否应该首先从数据库检查用户名是否匹配,如果错误则应返回错误的凭据?我从互联网上找到了 userdetailservice ,大多数人都是这样编写代码的。那我们怎么知道id不匹配呢.,,?
非常感谢
UserDeatilSerivce.java
package com.group6.shopping.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.group6.shopping.members.dao.MembersDAO;
import org.springframework.ui.Model;
public class CustomMemDetailsService implements UserDetailsService{
@Autowired
MembersDAO membersDAO;
@Override
public UserDetails loadUserByUsername(String memId) {
System.out.println("loaduserByusername");
CustomMemDetails members = null;
try {
members = membersDAO.getMemById(memId);
if(members == null) {
throw new UsernameNotFoundException("username " + memId + " not found");
}
System.out.println("**************Found user***************");
System.out.println("id : " + members.getUsername());
return members;
} catch (Exception e) {
e.printStackTrace();
}
return members;
}
}
security-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<security:http pattern="/resources/**" security="none"/>
<security:http>
<security:intercept-url pattern="/everyone/**" access="permitAll"/>
<security:intercept-url pattern="/member/**" access="hasRole('ROLE_MEMBER')"/>
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
<security:form-login login-page="/everyone/login"
login-processing-url="/everyone/login/loginProcess"
default-target-url="/"
authentication-failure-handler-ref="loginFailureHandler"/>
<!-- 최대 한 개의 세션만 생성되도록 -->
<security:session-management invalid-session-url="/everyone/login">
<security:concurrency-control max-sessions="1"
expired-url="/everyone/login"
error-if-maximum-exceeded="true" />
</security:session-management>
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="customMemService">
<security:password-encoder hash="bcrypt"/>
</security:authentication-provider>
</security:authentication-manager>
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<bean id="loginFailureHandler" class="com.group6.shopping.security.LoginFailureHandler"/>
<context:component-scan base-package="com.group6.shopping.security" />
<bean id="customMemService" class="com.group6.shopping.security.CustomMemDetailsService" />
</beans>
LoginFailureHandler.java
package com.group6.shopping.security;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String msg = "";
if(exception instanceof UsernameNotFoundException){
System.out.println("username error");
msg = "Wrong id or password. Please re-enter";
}else if (exception instanceof BadCredentialsException){
System.out.println("bad credential");
msg = "Wrong id or password. Please re-enter";
}
request.setAttribute("msg", msg);
request.getRequestDispatcher("/everyone/login?error").forward(request, response);
}
}
In the Spring Security, they automatically match input username and password with the DB saved username and password. It returns bad credential when password is not matched. However, in my code, as long as I know, if the username also does not match with DB saved username they should return bad credential. However, in my code, bad credential are shown only when username is correct and password is wrong and when username is not in DB it throws usernmaenotfoundexception.
I know I wrote usernamenotfoundexception in loaduserByusername. However, should it be first to check from DB whether username is matched and if it is wrong then bad credentials should be returned? I found userdetailservice from internet and most of people wrote the code this way. Then how should we know id not matched.,,?
Thank you so much
UserDeatilSerivce.java
package com.group6.shopping.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.group6.shopping.members.dao.MembersDAO;
import org.springframework.ui.Model;
public class CustomMemDetailsService implements UserDetailsService{
@Autowired
MembersDAO membersDAO;
@Override
public UserDetails loadUserByUsername(String memId) {
System.out.println("loaduserByusername");
CustomMemDetails members = null;
try {
members = membersDAO.getMemById(memId);
if(members == null) {
throw new UsernameNotFoundException("username " + memId + " not found");
}
System.out.println("**************Found user***************");
System.out.println("id : " + members.getUsername());
return members;
} catch (Exception e) {
e.printStackTrace();
}
return members;
}
}
security-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<security:http pattern="/resources/**" security="none"/>
<security:http>
<security:intercept-url pattern="/everyone/**" access="permitAll"/>
<security:intercept-url pattern="/member/**" access="hasRole('ROLE_MEMBER')"/>
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')"/>
<security:form-login login-page="/everyone/login"
login-processing-url="/everyone/login/loginProcess"
default-target-url="/"
authentication-failure-handler-ref="loginFailureHandler"/>
<!-- 최대 한 개의 세션만 생성되도록 -->
<security:session-management invalid-session-url="/everyone/login">
<security:concurrency-control max-sessions="1"
expired-url="/everyone/login"
error-if-maximum-exceeded="true" />
</security:session-management>
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="customMemService">
<security:password-encoder hash="bcrypt"/>
</security:authentication-provider>
</security:authentication-manager>
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<bean id="loginFailureHandler" class="com.group6.shopping.security.LoginFailureHandler"/>
<context:component-scan base-package="com.group6.shopping.security" />
<bean id="customMemService" class="com.group6.shopping.security.CustomMemDetailsService" />
</beans>
LoginFailureHandler.java
package com.group6.shopping.security;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String msg = "";
if(exception instanceof UsernameNotFoundException){
System.out.println("username error");
msg = "Wrong id or password. Please re-enter";
}else if (exception instanceof BadCredentialsException){
System.out.println("bad credential");
msg = "Wrong id or password. Please re-enter";
}
request.setAttribute("msg", msg);
request.getRequestDispatcher("/everyone/login?error").forward(request, response);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我对 Spring Security 流程缺乏了解。它实际上在 userdetailservice 运行后检查 id 和密码。所以,我只是删除抛出新的 UsernameNotFoundException 并返回新的 CustomMemDetails();
然后在登录失败 handler.java 中检查异常是否为 DisabledException
I had miss understanding of spring security flow. It actually checks id and password after userdetailservice is ran. So, I just delete throws new UsernameNotFoundException and return new CustomMemDetails();
then in login failure handler.java just check exception is DisabledException