如何使用 AuthenticationProvider Spring Security?

Posted

技术标签:

【中文标题】如何使用 AuthenticationProvider Spring Security?【英文标题】:How to use AuthenticationProvider Spring Security? 【发布时间】:2016-07-19 07:38:57 【问题描述】:

我是 Spring 新手,我需要一些关于使用 Spring Security 进行身份验证的帮助。另外,如果有人可以,最好澄清一些时刻,(我会用 (#1-..) 标记它们)因为一开始对我来说有很多“魔法”和奇怪的事情,即使在阅读了教程和文档之后 =(.

所以,我尝试实现 AuthenticationProvider,如果我理解了 authenticate() 方法中的所有内容,我可以组织我的特定身份验证逻辑。 所以我的代码看起来像:

( (#1)如果我理解正确,Spring 会自动创建名称为 value="customAuth" 的 bean,并且无需在任何上下文文件中说明此 bean。我说的对吗?) CustomAuthenticationProvider

@Service(value = "customAuth")
public class CustomAuthenticationProvider implements AuthenticationProvider
    @Autowired
    public Storages storage;

    @Override
    @Transactional
    public Authentication authenticate(Authentication authentication) throws AuthenticationException 
    String login = authentication.getName();
    String password = authentication.getCredentials().toString();
    final User user = storage.uSM.findByAuthorization(login, password);
    if (user==null)
        return null;
     else 
        return new UsernamePasswordAuthenticationToken(login, password);
    
    

    @Override
    public boolean supports(Class<?> authentication) 
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
    

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
    <servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
        classpath:/resources/spring-context.xml
        classpath:/resources/spring-security.xml
        </param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>

    <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/resources/spring-context.xml
        classpath:/resources/spring-security.xml
    </param-value>
    </context-param>

    <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>

    <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/secret/page</url-pattern>
    </filter-mapping>
    <mvc:default-servlet-handler/>
</web-app>

spring-security.xml

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security.xsd">

    <http auto-config="true" use-expressions="true">
    <intercept-url pattern="/secret/page" access="isAuthenticated()"/>
    <form-login
        login-page="/sign/in"
        default-target-url="/secret/page"
        authentication-failure-url="/sign/in"
        password-parameter="password"
        username-parameter="username"
    />
    </http>

    <authentication-manager>
    <authentication-provider ref="customAuth"/>
    </authentication-manager>
</beans:beans>

下一个是带有自定义登录表单的 in.jsp 文件。正如我所读到的,此表单将默认发送到 /login(我知道我们可以通过设置 login-processing-url 来更改它)。第二个问题(#2)是关于这个“/login”的。正如我所理解的,当我们将表单发布到 /login 时,我们会将其发送到由 Spring 类创建的某个类,该类将管理它并向我们在此处设置的 AuthorizationProvider 提供必要的数据:&lt;authentication-provider ref="customAuth"/&gt;?还是我错了? 无论如何,它不起作用。 A尝试了很多变种,但没有一个不起作用。所以这里是我的 in.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
    <c:if test="$failed==1">  
        <font color="red">
        Authentication failed. Wrong email/password.
        </font>
    </c:if>

    <form action="$pageContext.servletContext.contextPath/login" method="POST">
        <label> E-mail </label>
        <input type="email" name="username" required><br>
        <label> Password </label>
        <input type="password" name="password" required><br>
        <input type="submit" value="Sign in"><br>
    </form>
    </body>
</html>

In.java @Controller:

@Controller
@RequestMapping ("/sign/in")
public class In 
    @RequestMapping (method = RequestMethod.GET)
    public String showForm(@RequestParam(required = false) Integer failed, ModelMap model)
    model.addAttribute("failed", failed);
    return "sign/in";
    

在这种情况下,在我发布我的表单后,它会将我重定向到 /login 并发生 404 错误,因为它不存在。

那么有人可以帮忙解决它吗?我将不胜感激任何解释、链接和想法。提前致谢。

【问题讨论】:

您遇到什么错误?堆栈跟踪? 实际上,当我尝试发布登录表单时出现 404 错误,因为它试图将我引至不存在的 /login 页面。 /login 实际上是 UsernamePasswordAuthenticationFilter 存在于 Spring Security 中。你可以试试我的回答。 【参考方案1】:

替代解决方案:

(#1)您应该使用“customAuth”作为 id 创建 bean,因为 spring 将引用此 ID 以使用 CustomAuthenticationProvider 类,并且只留下 @Service 没有任何参数应该可以解决问题。(您可以尝试如果你愿意)

(#2)在您提交登录页面in.jsp 后,spring 将处理login-processing-url=/login 事件中您未在&lt;form-login&gt; 中声明的信息。是的,春天将参考CustomAuthenticationProvider。如果您的登录成功,spring 会将您重定向到default-target-url="/secret/page"。如果登录失败,将重定向到可用的允许页面。

我修改了你的部分代码

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
    classpath:/resources/spring-context.xml
    classpath:/resources/spring-security.xml
    </param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<mvc:default-servlet-handler/>

spring-security.xml

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security.xsd">

<http auto-config="true" use-expressions="true">
<intercept-url pattern="/sign/in" access="permitAll()" /> 
<intercept-url pattern="/**" access="isAuthenticated()" />

<form-login
    login-page="/sign/in"
    default-target-url="/secret/page"
    authentication-failure-url="/sign/in"
    password-parameter="password"
    username-parameter="username"
/>
</http>

<authentication-manager>
<authentication-provider ref="customAuth"/>
</authentication-manager>

<beans:bean id="customAuth" class="xx.xxx.xxxx.CustomAuthenticationProvider" />
</beans:beans>

in.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>JSP Page</title>
</head>
<body>
<c:if test="$failed==1">  
    <font color="red">
    Authentication failed. Wrong email/password.
    </font>
</c:if>

<form action="<c:url value='/login />'" method="POST">
    <label> E-mail </label>
    <input type="email" name="username" required><br>
    <label> Password </label>
    <input type="password" name="password" required><br>
    <input type="submit" value="Sign in"><br>
</form>
</body>

404的原因是因为你需要用/secret/page定义控制器并返回你需要的JSP文件。

希望对您有所帮助。

【讨论】:

非常感谢您的帮助和解释。我很抱歉回答很长。它现在工作正常,我可以看到我被重定向到登录/in?failed=1,所以它工作正常(可能我在我的类中与数据库一起工作的某个地方犯了一个错误)。 如果你想得到一个参数'failed'你可以在方法控制器中添加@RequestParam,你可以得到failed的值,welcome and gud luk :)

以上是关于如何使用 AuthenticationProvider Spring Security?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用本机反应创建登录以及如何验证会话

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何使用 AngularJS 的 ng-model 创建一个数组以及如何使用 jquery 提交?

如何使用laravel保存所有行数据每个行名或相等

如何使用 Math.Net 连接矩阵。如何使用 Math.Net 调用特定的行或列?

WSARecv 如何使用 lpOverlapped?如何手动发出事件信号?