首页 > 解决方案 > Cannot access to Main Page after using spring-security, although login is successful

问题描述

I want to add security part to the project and I am using spring security for providing backend security. When I added custom login filter that extends AbstractAuthenticationProcessingFilter of spring security, I got an error about cross origin problem. Now I added http.cors(); to the WebSecurityConfig and I do not get cross origin errors anymore.

I am sending a request to the backend http://localhost:8081/user/sys-role/verifyTargetUrl. Now, the exact error is Uncaught (in promise) Error: Infinite redirect in navigation guard at eval (vue-router.esm-bundler.js?6c02:2913). So somehow frontend vue-router guards find itself in an infinite loop. I will appreciate any of your help.

UPDATE:

It turned out that I don't get the response code as 200 and that causes the infinite loop in vue-router. My question becomes pure spring-security question because there seems to be no issue with vue-router. I send a post request to http://localhost:8081/user/sys-role/verifyTargetUrl but my request does not enter to the PostMapping in backend. It rather enters CustomAuthenticationEntryPoint shown below and sets the code to 504. But in verifyTargetUrl of backend I set it to 200. Besides, onAuthenticationSuccess of CustomAuthenticationSuccessfulHandler is also called in the backend.

public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {

    Message msg=new Message();
    msg.setCode(504);
    msg.setMsg("authenticate fail");

    httpServletResponse.setStatus(HttpServletResponse.SC_OK);
    httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
    httpServletResponse.setCharacterEncoding(StandardCharsets.UTF_8.toString());
    httpServletResponse.getWriter().write(JSON.toJSONString(msg));
}

}

The console of the browser:

config: {url: "http://localhost:8081/user/sys-role/verifyTargetUrl", method: "post", data: "{"userId":1017,"targetUrl":"/Main"}", headers: {…}, transformRequest: Array(1), …} data: {code: 504, msg: "authenticate fail"}

UPDATE 2: More Code

CustomJSONLoginFilter.java

public class CustomJSONLoginFilter  extends AbstractAuthenticationProcessingFilter {

private final ISysUserService iUserService;

public CustomJSONLoginFilter(String defaultFilterProcessesUrl, ISysUserService iUserService) {
    super(new AntPathRequestMatcher(defaultFilterProcessesUrl, HttpMethod.POST.name()));
    this.iUserService = iUserService;
}


@Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
    JSONObject requestBody=  getRequestBody(httpServletRequest);
    String username= requestBody.getString("username");
    String password= requestBody.getString("password");

    // get user info  by username
    SysUser sysUser= iUserService.getUserInfoByUsername(username);

    //verify password
    String encorderType=EncryptionAlgorithm.ENCODER_TYPE.get(1);
    PasswordEncoder passwordEncoder =EncryptionAlgorithm.ENCODER_MAP.get(encorderType);
    System.out.println(passwordEncoder);
    System.out.println(sysUser);
    System.out.println(password);
    if(sysUser==null){
        throw new UsernameNotFoundException("can't find userinfo by username:"+username);
    }else if(!passwordEncoder.matches(password,sysUser.getPassword())){
        throw new BadCredentialsException("password wrong!");
    }else{
        List<SysRole> list= iUserService.findRolesByUsername(username);
        List<SimpleGrantedAuthority> simpleGrantedAuthorities=  new ArrayList<SimpleGrantedAuthority>();


        Iterator<SysRole> i=list.iterator();
        while(i.hasNext()){
            simpleGrantedAuthorities.add(new SimpleGrantedAuthority(i.next().getRoleName()));
        }

        return new UsernamePasswordAuthenticationToken(username,password,simpleGrantedAuthorities);
    }

}


private JSONObject getRequestBody(HttpServletRequest request) throws AuthenticationException{
    try {
        StringBuilder stringBuilder = new StringBuilder();
        InputStream inputStream = request.getInputStream();
        byte[] bs = new byte[StreamUtils.BUFFER_SIZE];
        int len;
        while ((len = inputStream.read(bs)) != -1) {
            stringBuilder.append(new String(bs, 0, len));
        }
        return JSON.parseObject(stringBuilder.toString());
    } catch (IOException e) {
        System.out.println("get request body error.");
    }
    throw new AuthenticationServiceException("invalid request body");
}

标签: springspring-bootauthenticationspring-securityvue-router

解决方案


我不会编写自定义安全性,而是使用 Spring Security,他们有一个强大的库并且已经为你解决了,这是一个配置问题!

我的方法很容易实现!我有一个存储用户类

Kotlin 代码

var username: String? = null
    var password: String? = null
    var active: Boolean = false
    var confirmationToken: String? = null // email confirmationToken sent @ registration and other admin functions
    var token: String? = null // If JWT token exist (not NULL or "") then the Networker is logged in with Client!
    var roles: String? = null
    var permissions: String? = null

ADD CONSTRUCTORS ....

    val roleList: List<String>
        get() = if (this.roles?.isNotEmpty()!!) {
            listOf(*this.roles?.split(",".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray()!!)
        } else ArrayList()
    
    val permissionList: List<String>
        get() = if (this.permissions?.isNotEmpty()!!) {
            listOf(*this.permissions?.split(",".toRegex())?.dropLastWhile { it.isEmpty() }?.toTypedArray()!!)
        } else ArrayList()

从那里我配置securityConfiguration


import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.util.matcher.AntPathRequestMatcher

@Configuration
@EnableWebSecurity
class SecurityConfiguration(private val userPrincipalDetailService: UserPrincipalDetailService) :
    WebSecurityConfigurerAdapter() {
    
    override fun configure(auth: AuthenticationManagerBuilder) {
        auth.authenticationProvider(authenticationProvider())
    }
    
    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http.authorizeRequests()
            .antMatchers("/index.html").permitAll()
            .antMatchers("/security/**").permitAll()
            .antMatchers("/profile/**").authenticated()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .and().formLogin()
            .defaultSuccessUrl("/profile/index", true)
            .loginProcessingUrl("/security/login")
            .loginPage("/security/login").permitAll()
            .usernameParameter("username")
            .passwordParameter("password")
            .and().logout()
            .invalidateHttpSession(true)
            .clearAuthentication(true)
            .deleteCookies("JSESSIONID")
            .logoutRequestMatcher(AntPathRequestMatcher("/logout"))
            .logoutSuccessUrl("/security/login")
            .and()
            .rememberMe().tokenValiditySeconds(2592000) // 2592000 = 30 days in Seconds
            .rememberMeParameter("rememberMe")
    }
    
    private fun authenticationProvider(): DaoAuthenticationProvider {
        val daoAuthenticationProvider = DaoAuthenticationProvider()
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder())
        daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailService)
        
        return daoAuthenticationProvider
    }
    
    @Bean
    internal fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }
}

如果你想学习 Spring Security 课程 - 你可以 学习罗马尼亚 Coder 的 Spring Boot Security


推荐阅读