[英]Spring Boot Form Login Custom UserDetailsService authorisation not working
我是 Spring Boot 的初學者,並且真的很難做到這一點。 我根本沒有發現 Spring 引導的安全性 API 非常直觀,但我正在嘗試得到它。
我將使用 MySql 和 JPA 從數據庫中獲取用戶,但最初只是為了確保安全腳手架有效,我只是硬編碼來自員工詳細信息服務的用戶。
經過很多麻煩,我設法讓基本身份驗證工作,但授權不起作用。 我已經編輯了問題以反映基本問題:
我知道在人們將此標記為重復之前還有其他問題,我已經完成了所有這些問題,他們都回答了我認為已經在我的應用程序中工作的基本答案。
最后 /home 路徑用於 home 方法,/mama 路徑用於角色 mama
這是代碼:
//AppSecurityConfig.java
package com.straightwalls.absencemanagement.config;
import com.straightwalls.absencemanagement.service.EmployeeDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
protected void configure(HttpSecurity http) throws Exception {
//Disabled for development
http.authorizeRequests()
.antMatchers("/mama").hasRole("MAMA")
.antMatchers("/home").hasAnyRole("ROLE_HEAD", "ROLE_MAMA")
.and()
.formLogin();
}
@Bean
/*
* Returning no op password encoder for now,
* as we are not encoding passwords as no registration
* implemented for Prototype. We would need to add the users from a separate service. W
*
* */
public PasswordEncoder getPasswordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
}
//EmployeeDetailsService
package com.straightwalls.absencemanagement.service;
import com.straightwalls.absencemanagement.model.Employee;
import com.straightwalls.absencemanagement.model.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Service
public class EmployeeDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
if (!username.equals("Mama")){
throw new UsernameNotFoundException(
"You got the wrong Username, should be mama"
);
}
Employee employee = new Employee();
Role role = new Role();
role.setName("HEAD");
employee
.setUsername(username)
.setPassword("1234")
.setRole(role);
return new EmployeePrincipal(employee);
}
}
//EmployeePrincipal.java
package com.straightwalls.absencemanagement.service;
import com.straightwalls.absencemanagement.model.Employee;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Collection;
public class EmployeePrincipal implements UserDetails {
private Employee employee;
//Added another default Constructor, incase
public EmployeePrincipal(){
}
public EmployeePrincipal(Employee employee){
this.employee = employee;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_HEAD"));
//return Arrays.asList(new SimpleGrantedAuthority("ROLE_" + employee.getRole().getName()));
}
@Override
public String getPassword() {
return employee.getPassword();
}
@Override
public String getUsername() {
return employee.getUsername();
}
/*
* Methods below are the rubbish methods, we keep as true for now
*
* */
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
//Login.java
package com.straightwalls.absencemanagement.api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LoginApi {
@RequestMapping("/")
public String index(){
return "Straight Walls absence management!";
}
@RequestMapping("/home")
public String home(){
return "Welcome to Home!";
}
/**
* This method can be deleted in the end
*
*/
@RequestMapping("/mama")
public String roleTest(){
return "This end point is only for Mama!";
}
}
//Employee.java
package com.straightwalls.absencemanagement.model;
import org.hibernate.annotations.Fetch;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@Entity
public class Employee {
@Id
private long id;
private String firstName;
private String lastName;
private String username;
private String password;
private String startDate;
@ManyToOne
@JoinColumn(name = "roleId", referencedColumnName = "id")
private Role role;
@ManyToOne
@JoinColumn(name = "departmentId", referencedColumnName = "id")
private Department department;
public Employee(){
}
public long getId() {
return id;
}
public Employee setId(long id) {
this.id = id;
return this;
}
public String getFirstName() {
return firstName;
}
public Employee setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public String getLastName() {
return lastName;
}
public Employee setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public String getUsername() {
return username;
}
public Employee setUsername(String username) {
this.username = username;
return this;
}
public String getPassword() {
return password;
}
public Employee setPassword(String password) {
this.password = password;
return this;
}
public String getStartDate() {
return startDate;
}
public Employee setStartDate(LocalDate startDate) {
this.startDate =
startDate.format(DateTimeFormatter.ISO_LOCAL_DATE);
return this;
}
public Role getRole() {
return role;
}
public Employee setRole(Role role) {
this.role = role;
return this;
}
public Department getDepartment() {
return department;
}
public Employee setDepartment(Department department) {
this.department = department;
return this;
}
}
Server Logs: 2021-04-21 07:42:12.151 INFO 10370 --- [ restartedMain] traightWallsAbsenceManagementApplication: Starting StraightWallsAbsenceManagementApplication using Java 16 on Peshotans-MacBook-Air.local with PID 10370 (/Users/peshotanpavri/java/IdeaProjects/StraightWallsAbsenceManagement /target/classes 由 peshotanpavri 在 /Users/peshotanpavri/java/IdeaProjects/StraightWallsAbsenceManagement 中啟動)2021-04-21 07:42:12.154 INFO 10370 --- [restartedMain] traightWallsAbsenceManagementApplication:沒有活動配置文件集,回退到默認配置文件:默認 2021-04-21 07:42:12.254 INFO 10370 --- [restartedMain].e.DevToolsPropertyDefaultsPostProcessor:DevTools 屬性默認處於活動狀態。 將“spring.devtools:add-properties”設置為“false”以禁用 2021-04-21 07:42.12.255 INFO 10370 --- [restartedMain].e:DevToolsPropertyDefaultsPostProcessor。 For additional web related logging consider setting the 'logging.level:web' property to 'DEBUG' 2021-04-21 07:42.14.065 INFO 10370 --- [ restartedMain].sdr.c:RepositoryConfigurationDelegate. Bootstrapping Spring Data JPA repositories in DEFAULT mode: 2021-04-21 07:42.14.203 INFO 10370 --- [ restartedMain].sdr.c:RepositoryConfigurationDelegate. 在 113 毫秒內完成 Spring 數據存儲庫掃描。 Found 1 JPA repository interfaces: 2021-04-21 07:42.15.235 INFO 10370 --- [ restartedMain] osbwembedded.tomcat:TomcatWebServer: Tomcat initialized with port(s): 8080 (http) 2021-04-21 07:42.15 。 :StandardEngine:啟動 Servlet 引擎。 [Apache Tomcat/9.0:45] 2021-04-21 07:42.15.404 INFO 10370 --- [ restartedMain] oac.c.C.[Tomcat].[localhost]:[/]: Initializing Spring embedded WebApplicationContext 2021- 04-21 07:42.15.405 INFO 10370 --- [ restartedMain] wsc:ServletWebServerApplicationContext: Root WebApplicationContext: initialization completed in 3147 ms 2021-04-21 07:42.15.642 INFO 10370 --- [ restartedMain] com.zaxxer.光:光數據源。 HikariPool-1 - 開始..:2021-04-21 07:42.16.670 INFO 10370 --- [restartedMain] com.zaxxer.hikari:HikariDataSource。 HikariPool-1 - Start completed: 2021-04-21 07:42.16.743 INFO 10370 --- [ restartedMain] o.hibernate.jpa.internal.util:LogHelper: HHH000204: Processing PersistenceUnitInfo [name: default] 2021-04- 21 07:42.16.859 信息 10370 --- [restartedMain] org.hibernate:版本:HHH000412。 Hibernate ORM core version 5.4.30:Final 2021-04-21 07:42.17.121 INFO 10370 --- [ restartedMain] o.hibernate.annotations.common:Version: HCANN000001. Hibernate Commons Annotations {5.1.2:Final} 2021-04-21 07:42.17.327 INFO 10370 --- [restartedMain] org.ZCB1F008EEBF5012C4EF9A2C36E574D600040000H:使用方言:HH org.hibernate.dialect:MySQL8Dialect 2021-04-21 07:42.18.359 INFO 10370 --- [restartedMain] ohetjpi:JtaPlatformInitiator: HHH000490: 使用 JtaPlatform 實現。 [org.hibernate.engine.transaction.jta.platform.internal:NoJtaPlatform] 2021-04-21 07:42.18.383 INFO 10370 --- [ restartedMain] j:LocalContainerEntityManagerFactoryBean: Initialized JPA EntityManagerFactory for persistence unit 'default' 2021- 04-21 07:42.18:458 WARN 10370 --- [restartedMain] JpaBaseConfiguration$JpaWebConfiguration。 spring.jpa.open-in-view 默認啟用,因此。 可以在視圖呈現期間執行數據庫查詢。 Explicitly configure spring.jpa:open-in-view to disable this warning 2021-04-21 07:42.18.737 INFO 10370 --- [ restartedMain] ossweb:DefaultSecurityFilterChain. 將使用 [org.springframework.security.web.context.request.async,WebAsyncManagerIntegrationFilter@7e4d562b 保護任何請求。 org.springframework.security.web.context,SecurityContextPersistenceFilter@657e3908。 org.springframework.security.web.header,HeaderWriterFilter@484dbda9。 org.springframework.security.web.csrf,CsrfFilter@358c0253。 org.springframework.security.web.authentication.logout,LogoutFilter@4596a3b。 org.springframework.security.web.authentication,UsernamePasswordAuthenticationFilter@6dceb9b9。 org.springframework.security.web.authentication.ui,DefaultLoginPageGeneratingFilter@697f408b。 org.springframework.security.web.authentication.ui,DefaultLogoutPageGeneratingFilter@6a227727。 org.springframework.security.web.authentication.www,BasicAuthenticationFilter@166853dc。 org.springframework.security.web.savedrequest,RequestCacheAwareFilter@185f798b。 org.springframework.security.web.servletapi,SecurityContextHolderAwareRequestFilter@7f7692e4。 org.springframework.security.web.authentication,AnonymousAuthenticationFilter@5406fd30。 org.springframework.security.web.session,SessionManagementFilter@66387082。 org.springframework.security.web.access,ExceptionTranslationFilter@44bb34bf。 org.springframework.security.web.access.intercept:FilterSecurityInterceptor@768269d7] 2021-04-21 07:42.18.981 INFO 10370 --- [restartedMain] ossconcurrent:ThreadPoolTaskExecutor: Initializing ExecutorService '221-04'7 42.19.784 INFO 10370 --- [ restartedMain] osbda:OptionalLiveReloadServer: LiveReload server is running on port 35729 2021-04-21 07:42.19.835 INFO 10370 --- [ restartedMain] osbwembedded.tomcat:TomcatWebServer: Tomcat started on port (s): 8080 (http) 與上下文路徑 '' 2021-04-21 07:42.19:851 INFO 10370 --- [restartedMain] traightWallsAbsenceManagementApplication。 Started StraightWallsAbsenceManagementApplication in 8.486 seconds (JVM running for 10:642) 2021-04-21 07:42.45.273 INFO 10370 --- [nio-8080-exec-1] oac.c.C.[Tomcat].[localhost] :[/]:初始化Z38008DD81C2F4D7985ECF6E0CE8AF1D1D1D DISPATCHERSERVELTERSEVELT'dispatcherServlet'2021-04-21 07:42.45.275信息10375 10370 ---------- 21 07:42.45.300 INFO 10370 --- [nio-8080-exec-1] osweb.servlet:DispatcherServlet:在 24 毫秒內完成初始化
我正在使用虛擬角色 HEAD 登錄。 所以我應該能夠訪問:/, /home 但不能訪問 /mama 我無法訪問 /home,即使角色已正確定義
In my base package, I have the following packages: config: With this config file, model: All entities api: Controllers repository: Repositories (Not used yet) service: Where I have EmployeeDetailsService & EmployeeDetails class
任何建議都將不勝感激,因為我希望這能奏效,但即使我輸入了用戶名 Mama 和密碼 Mama 並嘗試使用 NoOpPasswordEncoder,它也不會拋出任何錯誤,只是不斷地說出錯誤的憑據
設法通過清理代碼並對grantedAuthorities 方法進行一些更改來解決此問題,該方法不需要ROLE_
還通過消除 ROLE_ 更改了 hasRole、hasAnyRole 和 hasAuthority 和 hasAnyAuthority。不確定為什么,但它現在可以工作。
此外,API 現在更容易理解了
這是更新的代碼:
@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
/*auth.inMemoryAuthentication()
.withUser("appuser").password("1234").roles("HEAD")
.and()
.withUser("Mama").password("Mama").roles("MAMA");*/
}
@Override
/*
* Now we have learnt the basics of Spring Security & Authrization method is completed.
* Lets fix Authentication first!
* Got it to work with hasAuthority & hasAnyAuthority but not with roles, not sure why, but it works atm
*
* */
protected void configure(HttpSecurity http) throws Exception {
//Disabled for development
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/mama").hasAuthority("MAMA")
.antMatchers("/home").hasAnyAuthority("HEAD", "MAMA")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/")
.defaultSuccessUrl("/home");
}
@Bean
/*
* Returning no op password encoder for now, as we are not encoding passwords as no registration
* implemented for Prototype. We would need to add the users from a separate service. W
*
* */
public PasswordEncoder getPasswordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
}
//EmployeeDetailsService.java
@Service
public class EmployeeDetailsService implements UserDetailsService {
@Override
/*
* First, we are testing the Employee details service, independent of the Database, just to make sure we have this part working,
* For the purpose of these prototypes, we wont use password encoder because we are not registering,
*
* */
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (!username.equals("Mama")){
throw new UsernameNotFoundException("You got the wrong Username, should be mama");
}
Employee employee = new Employee();
Role role = new Role();
role.setName("HEAD");
employee
.setUsername(username)
.setPassword("1234")
.setRole(role);
return new EmployeePrincipal(employee);
}
}
//EmployeePrincipal.java
public class EmployeePrincipal implements UserDetails {
private Employee employee;
public EmployeePrincipal(Employee employee){
this.employee = employee;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(employee.getRole().getName()));
return authorities;
}
@Override
public String getPassword() {
return employee.getPassword();
}
@Override
public String getUsername() {
return employee.getUsername();
}
/*
* Methods below are the rubbish methods, we keep as true for now
*
* */
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
@RestController
public class LoginApi {
@RequestMapping("/")
public String index(){
return "Index"
}
@RequestMapping("/home")
public String home(){
return "Home!";
}
/*
* This method can be deleted in the end
* */
@RequestMapping("/mama")
public String roleTest(){
return "This end point is only for Mama!";
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.