簡體   English   中英

Spring 引導表單登錄自定義用戶詳細信息服務授權不起作用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM