SpringSecurity自定义登录认证

需求

Spring Security默认的登录表单只有username和password,但实际业务中我们可能需要使用其他的字段校验,因此需要重写认证部分。

web.xml

<!-- 配置SpringSecurity过滤器 -->
    <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>

security.xml

spring security的配置,需要web.xml扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <!-- 以下页面不被拦截 -->
    <http pattern="/login/**"  security="none"></http>
    <http pattern="/static/**" security="none"></http>

    <!-- 页面拦截规则 -->
    <http use-expressions="false">
        <intercept-url pattern="/**" access="ROLE_USER" />

        <form-login login-page="/login/login.jsp" 
                    authentication-failure-url="/login/login.jsp?error=true"
                    login-processing-url="/login.do"
                    default-target-url="/index.jsp"
                    authentication-details-source-ref="authenticationDetailsSource"
                    />
        <logout logout-url="/logout.do" logout-success-url="/login/login.jsp"/>
        <csrf disabled="true"/>
        <headers>
            <frame-options policy="SAMEORIGIN"/>
        </headers>
    </http>

    <!-- 认证管理器 -->
    <authentication-manager>
         <!---使用自定义的认证管理器->
        <authentication-provider ref="authenticationProvider" ></authentication-provider>
    </authentication-manager>
   <!---自定义认证管理器->
    <beans:bean id="authenticationProvider" class="com.controller.login.LoginAuthenticationProvider"></beans:bean>
    <beans:bean id="authenticationDetailsSource" class="com.controller.login.LoginAuthenticationDetailsSource"></beans:bean>

</beans:beans>

自定义类

LoginAuthenticationDetailsSource
public class LoginAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> {

    @Override
    public WebAuthenticationDetails buildDetails(HttpServletRequest context) {
        //DetailSource返回自定义的认证对象 
        return new LoginWebAuthenticationDetails(context);
    }
}
LoginWebAuthenticationDetails

这个类用于收集表单提交的参数

public class LoginWebAuthenticationDetails extends WebAuthenticationDetails{
    
    private static final long serialVersionUID = 336993541165304236L;
    
    private String serverRandomId;
    private String encryptedClientRandom;
    private String encryptedInputValue;
    private String username;
    private String password;

    public LoginWebAuthenticationDetails(HttpServletRequest request) {
        super(request);
        serverRandomId = request.getParameter("serverRandomId");
        encryptedClientRandom = request.getParameter("encryptedClientRandom");
        encryptedInputValue = request.getParameter("encryptedInputValue");
        username = request.getParameter("username");
        password = request.getParameter("password");
    }

    public String getServerRandomId() {
        return serverRandomId;
    }

    public String getEncryptedClientRandom() {
        return encryptedClientRandom;
    }

    public String getEncryptedInputValue() {
        return encryptedInputValue;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

}

LoginAuthenticationProvider

这个类用于登录认证逻辑的判断

public class LoginAuthenticationProvider implements AuthenticationProvider{
    
    @Autowired
    private GlobalPermissionService globalPermissionService;
    @Autowired
    private ISysAccountService sysAccountService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
       // 这里通过我们自定义的对象,取出收集的表单参数进行逻辑验证
        LoginWebAuthenticationDetails details = (LoginWebAuthenticationDetails) authentication.getDetails();
        String encryptedClientRandom = details.getEncryptedClientRandom();
        String username = details.getUsername();
       // 这里是验证逻辑
        if (验证失败) {
            throw new DisabledException("用户名或者密码不正确!");
        } 
        // 授权
        List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
        List<GrantedAuthority> list = globalPermissionService.getUserGrantedAuthority(username);
        grantedAuths.addAll(list);
        // 验证成功 返回这个对象
        return new UsernamePasswordAuthenticationToken(username, "", grantedAuths);
    }

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

}

登录页面

<form action="${pageContext.request.contextPath}/login.do" id="loginForm" method="post">
       <table class="table" id="LoginBox">
            <tr>
               <td id="logo"></td>
            </tr>
            <tr style="height:80px;">
               <td style="vertical-align: bottom;text-align:left;"><span class="loginText">用户名</span></td>
            </tr>
            <tr>
               <td><input type="text" class="form-control inputSize" name="username" id="username"></td>
            </tr>
            <tr style="height:40px;">
               <td style="text-align:left;"><span class="loginText">密码</span></td>
            </tr>
            <tr>
                <td>
                    <input type="password" class="form-control inputSize" name="password" id="password" onKeyDown="keydownEvent()">
                </td>
            </tr>
             <tr>
                <td>
                    <span style="color:red;margin-left: 25px;">${SPRING_SECURITY_LAST_EXCEPTION.message}</span>
                </td>
            </tr>
            <tr>
               <td>
                 <input type="button" class="btn btn-self-blue" value="登录" id="LoginBtn"/>
               </td>
            </tr>
          
       </table>
    </form>

登录页面注意:
如果验证失败,我们还跳转到登陆页面,同时Spring Security会在session中存储错误信息,错误信息的获取使用 ${SPRING_SECURITY_LAST_EXCEPTION.message}

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security提供了很多默认的权限认证方式,但是我们也可以自定义权限认证方式。下面是一个简单的示例: 首先,我们需要实现一个自定义的UserDetailsService,该接口用于从数据库或其他数据源中获取用户信息。该接口中有一个方法loadUserByUsername,用于根据用户名获取用户信息。 ```java @Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if(user == null) { throw new UsernameNotFoundException("User not found with username: " + username); } return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>()); } } ``` 然后,我们需要创建一个自定义的AuthenticationProvider,该类实现了Spring Security提供的AuthenticationProvider接口,用于自定义认证逻辑。在该类中,我们需要重写authenticate方法,该方法接收一个Authentication对象,该对象包含了用户输入的用户名和密码。我们可以通过该对象获取用户输入的用户名和密码,然后根据我们的认证逻辑进行认证,最后返回一个Authentication对象,该对象包含了认证后的用户信息。 ```java @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Autowired private CustomUserDetailsService userDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String username = authentication.getName(); String password = authentication.getCredentials().toString(); UserDetails userDetails = userDetailsService.loadUserByUsername(username); if(password.equals(userDetails.getPassword())) { return new UsernamePasswordAuthenticationToken(username, password, userDetails.getAuthorities()); } else { throw new BadCredentialsException("Invalid username/password"); } } @Override public boolean supports(Class<?> authentication) { return authentication.equals(UsernamePasswordAuthenticationToken.class); } } ``` 最后,我们需要在Security配置类中使用我们的自定义认证方式。我们可以通过重写configure(AuthenticationManagerBuilder auth)方法来配置我们的认证方式。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomAuthenticationProvider authProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic(); } } ``` 以上就是一个简单的Spring Security自定义权限认证的示例。通过自定义UserDetailsService和AuthenticationProvider,我们可以实现自己的认证逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值