java - Springboot Security + AngularJS Application + Memory 和 UserService 认证 + 自定义登录页面
问题描述
我正在为具有以下要求的新应用程序的设置而苦苦挣扎:
- 内存中用户的身份验证(API 使用)
- 来自 UserDetailsService (mysql db) 的用户身份验证
- 用于数据获取和更新的 API 路径
- MySQL 用户的 AngularJS 应用程序
问题:
如果我使用自定义登录页面,则基于 sql 用户的用户身份验证不再起作用。默认登录页面有效并将用户重定向到后端页面。问题是,用户名没有从我添加的 UserDetailsService 传递给方法 loadUserByUsername。
我必须设置什么,某些 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
解决方案
推荐阅读
- angular - Angular ngFor 在 svg 中给出错误,即使它可以编译
- git - Git是否可以显示子模块的当前标签?
- r - 减法列到R中下一行的另一列
- ios - @EnvironmentObject 中的 @Published 属性不会更新我的应用程序的根视图
- dataframe - 读取具有空值的 spark csv 而不转换为 null
- php - Access Special Character Key from STD array in PHP
- r - How to use/understand "%%"
- function - passing a function pointer to a method
- angular - 如何正确处理与两个不同环境(DEV 和 PROD)相关的不同 Firebase Cloud Function API 端点?
- r - 忽略 NA 分数函数异常值包 R