首页 > 解决方案 > Springboot Security + AngularJS Application + Memory 和 UserService 认证 + 自定义登录页面

问题描述

我正在为具有以下要求的新应用程序的设置而苦苦挣扎:

  1. 内存中用户的身份验证(API 使用)
  2. 来自 UserDetailsS​​ervice (mysql db) 的用户身份验证
  3. 用于数据获取和更新的 API 路径
  4. MySQL 用户的 AngularJS 应用程序

问题:

  1. 如果我使用自定义登录页面,则基于 sql 用户的用户身份验证不再起作用。默认登录页面有效并将用户重定向到后端页面。问题是,用户名没有从我添加的 UserDetailsS​​ervice 传递给方法 loadUserByUsername。

  2. 我必须设置什么,某些 API 路径的身份验证是按请求进行的(因此每个请求都需要在基本身份验证中发送正确的用户 + 密码),并且后端的用户应该有一个会话,该会话存储一段定义的时间

这是我现在的设置:用户详细信息服务

@Service class AccountDetailsServiceImpl : UserDetailsService {
@Autowired
private lateinit var accountRepository: AccountRepository

@Throws(UsernameNotFoundException::class)
override fun loadUserByUsername(username: String): AccountDetails {
    val account = accountRepository.getAccountByUsername(username)
    if (account != null) {
        val accountDetails =  AccountDetails(account)
        return accountDetails
    }
    throw UsernameNotFoundException("Could not find account $username")
}}

WebSecurityConfigurerAdapter

class MultiHttpSecurityConfiguration : WebSecurityConfigurerAdapter() {   
    @Autowired
    private lateinit var accountDetailsService: UserDetailsService
@Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

    @Autowired
    override fun configure(auth: AuthenticationManagerBuilder) {
        val daoAuth = DaoAuthenticationProvider()
        daoAuth.setUserDetailsService(accountDetailsService)
        daoAuth.setPasswordEncoder(passwordEncoder())
        auth.authenticationProvider(daoAuth)

        auth
            .inMemoryAuthentication()
            .withUser(usr1).password(passwordEncoder().encode(pw1)).authorities("EXTERNALSERVICEUSER1")
            .and()
            .withUser(usr2).password(passwordEncoder().encode(pw2)).authorities("EXTERNALSERVICEUSER2")
            .and()
            .withUser(usr3).password(passwordEncoder().encode(pw3)).authorities("ADMIN")
    }

    override fun configure(http: HttpSecurity) {
        http
            .authorizeRequests()
            .antMatchers(
                "/app/**",
                "/dist/**",
                "/locales/**",
                "/src/images/**",
                "/src/locales/**",
                "/error",
                "/backend/login",
                "/login" ,
                "/resources/**"
            ).permitAll()
            .antMatchers("/backend/**").hasAnyAuthority("ADMIN", "MANAGER")
            .and()
            .formLogin()
            .defaultSuccessUrl("/backend")
            .loginPage("/login")
            .and()
            .logout().logoutSuccessUrl("/login")
            .and()
            .httpBasic()

        http
            .authorizeRequests()
            .antMatchers(
                "/api/*/path...",
                "/api/*/path...",
                "/api/*/path...").hasAnyRole("EXTERNALSERVICEUSER1", "EXTERNALSERVICEUSER2")
            .antMatchers(
                "/api/*/path...",
                "/api/*/path...",
                "/api/*/path..."
            ).hasAnyAuthority("ADMIN","MANAGER", "USER")
            .antMatchers(
                "/api/*/path"
            ).hasAnyAuthority("ADMIN", "USER")
            .antMatchers(
                "/api/*/adminOnlyPaths../**",
            ).hasAnyAuthority("ADMIN")

        http.csrf().disable()
    }}

class MultiHttpSecurityConfiguration : WebSecurityConfigurerAdapter() {   
    @Autowired
    private lateinit var accountDetailsService: UserDetailsService
@Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

    @Autowired
    override fun configure(auth: AuthenticationManagerBuilder) {
        val daoAuth = DaoAuthenticationProvider()
        daoAuth.setUserDetailsService(accountDetailsService)
        daoAuth.setPasswordEncoder(passwordEncoder())
        auth.authenticationProvider(daoAuth)

        auth
            .inMemoryAuthentication()
            .withUser(usr1).password(passwordEncoder().encode(pw1)).authorities("EXTERNALSERVICEUSER1")
            .and()
            .withUser(usr2).password(passwordEncoder().encode(pw2)).authorities("EXTERNALSERVICEUSER2")
            .and()
            .withUser(usr3).password(passwordEncoder().encode(pw3)).authorities("ADMIN")
    }

    override fun configure(http: HttpSecurity) {
        http
            .authorizeRequests()
            .antMatchers(
                "/app/**",
                "/dist/**",
                "/locales/**",
                "/src/images/**",
                "/src/locales/**",
                "/error",
                "/backend/login",
                "/login" ,
                "/resources/**"
            ).permitAll()
            .antMatchers("/backend/**").hasAnyAuthority("ADMIN", "MANAGER")
            .and()
            .formLogin()
            .defaultSuccessUrl("/backend")
            .loginPage("/login")
            .and()
            .logout().logoutSuccessUrl("/login")
            .and()
            .httpBasic()

        http
            .authorizeRequests()
            .antMatchers(
                "/api/*/path...",
                "/api/*/path...",
                "/api/*/path...").hasAnyRole("EXTERNALSERVICEUSER1", "EXTERNALSERVICEUSER2")
            .antMatchers(
                "/api/*/path...",
                "/api/*/path...",
                "/api/*/path..."
            ).hasAnyAuthority("ADMIN","MANAGER", "USER")
            .antMatchers(
                "/api/*/path"
            ).hasAnyAuthority("ADMIN", "USER")
            .antMatchers(
                "/api/*/adminOnlyPaths../**",
            ).hasAnyAuthority("ADMIN")

        http.csrf().disable()
    }}

登录页面

<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
  <meta charset="UTF-8">
  <title>Login Page</title>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.slim.min.js"></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js'></script>
  <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" type="text/css" id="bootstrap-css">
  <script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
  <link href="/css/backendLogin.css" type="text/css"  rel="stylesheet"/>
</head>
<body>
<div class="sidenav">
  <div class="login-main-text">
    <h1>Login Page</h1>
  </div>
</div>
<div class="main">
  <div class="col-md-6 col-sm-12">
    <div class="login-form">
      <h3>Login here </h3>
      <hr class="solid-orange">
      <form name="f" th:action="@{/login}" method="post">
        <div class="form-group">
          <label>User Name</label>
          <input type="text" class="form-control" placeholder="User Name">
        </div>
        <div class="form-group">
          <label>Password</label>
          <input type="password" class="form-control" placeholder="Password">
        </div>
        <button type="submit" class="btn">Login</button>
      </form>
    </div>
  </div>
</div>
</body>
</html>

安全控制器

    @RestController
@RequestMapping("/")
class WebController() {
    private val logger = LoggerFactory.getLogger(WebController::class.java)

    @GetMapping("backend")
    fun showBackend(): ModelAndView {
        logger.info("Show page backend")
        return ModelAndView("backend")
    }

    @GetMapping("login")
    fun showLogin(
        @RequestParam(value = "error", required = false) error: String?,
        @RequestParam(value = "logout", required = false) logout: String?
    ): ModelAndView {
        logger.info("Show page backend")
        return ModelAndView("login")
    }

    @GetMapping("em")
    fun showEmergency(@RequestParam(value = "id", required = false) id: String?
    ): ModelAndView {
        logger.info("Show emergency page $id")
        return ModelAndView("emergency-case")
    }
}

资源文件夹中的项目结构如下所示 -src --main --kotlin --resources ---resources ----css ----images ---static ----angular-app ---templates ----backend.html ----login.html

标签: javaspring-bootspring-security

解决方案


推荐阅读