简体   繁体   English

我的 Spring Boot 项目中基于角色的授权

[英]Role based authorization in my Spring Boot project

Here is my SuccessHandler class这是我的 SuccessHandler 类

package com.myproject.configure;
    
import java.io.IOException;
import java.rmi.AccessException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

@Component
public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler  {
    
//  @Override
//  protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException  {
//      
//      String targetUrl = determineTargetUrl(authentication);
//      
//      System.out.println("Its a Target URL ---" + targetUrl);
//      if (response.isCommitted()) {
//          return;
//      }
//      RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
//      redirectStrategy.sendRedirect(request, response, targetUrl);
//  }
    
    protected String determineTargetUrl(Authentication authentication) {
        
        String url = "/login?error=true";

        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        List<String> roles = new ArrayList<String>();
        for (GrantedAuthority a : authorities) {
            roles.add(a.getAuthority());
        }
        
        if (roles.contains("SITE_ADMIN")) {
            System.out.println(roles.toString());
            url = "/admin/home";
        }
        else if (roles.contains("SITE_USERS")) {
            url = "/users/index";
            
        }
        
        return url;
        
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
        String redirectUrl = determineTargetUrl(authentication);
        
        if (redirectUrl == null) {
            throw new AccessException(redirectUrl);
        }
        new DefaultRedirectStrategy().sendRedirect(request, response, redirectUrl);
    }
}

Here I define two different Role one is "ADMIN" and another is "USER"这里我定义了两个不同的角色,一个是“ADMIN”,另一个是“USER”

I have two different Entity class for my Users and another for Role.我的用户有两个不同的实体类,角色有另一个。 I have two different destinations for my different roles.对于不同的角色,我有两个不同的目的地。 But when I run my application and log in successfully only "USER" role can see its page but "ADMIN" role user cannot see their page.但是当我运行我的应用程序并成功登录时,只有“USER”角色可以看到它的页面,而“ADMIN”角色用户看不到他们的页面。 But I can see the admin print statement in my console.但是我可以在控制台中看到 admin print 语句。 "It's an ADMIN!!!!!". “这是管理员!!!!!”。 What to do ?该怎么办 ? or where is my bug?或者我的错误在哪里?

Here is my Entities class:这是我的实体类:

package com.myproject.entities;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "users")
public class Users {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_users")
    private int idUsers;
    private String userName;
    private String password;
    
    @ManyToOne(cascade = CascadeType.ALL)
    private UserRole userRole;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "id_users")
    List<Recruitment> recruitments = new ArrayList<>();
    
    public Users() {
    }

    public Users(String userName, String password, UserRole userRole, List<Recruitment> recruitments) {
        this.userName = userName;
        this.password = password;
        this.userRole = userRole;
        this.recruitments = recruitments;
    }

    public int getIdUsers() {
        return idUsers;
    }

    public String getUserName() {
        return userName;
    }

    public String getPassword() {
        return password;
    }

    public UserRole getUserRole() {
        return userRole;
    }

    public List<Recruitment> getRecruitments() {
        return recruitments;
    }

    public void setIdUsers(int idUsers) {
        this.idUsers = idUsers;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setUserRole(UserRole userRole) {
        this.userRole = userRole;
    }

    public void setRecruitments(List<Recruitment> recruitments) {
        this.recruitments = recruitments;
    }

    @Override
    public String toString() {
        return "Users [idUsers=" + idUsers + ", userName=" + userName + ", password=" + password + ", userRole="
                + userRole + ", recruitments=" + recruitments + "]";
    }

    
    
    
}
package com.myproject.entities;

import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "user_role")
public class UserRole {

    @Id
    @Column(name = "iduser_role")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int idUserRole;
    private String roleName;
    
    @OneToMany(mappedBy = "userRole")
    private List<Users> users;

    public UserRole() {
    }

    public int getIdUserRole() {
        return idUserRole;
    }

    public String getRoleName() {
        return roleName;
    }

    public List<Users> getUsers() {
        return users;
    }

    public void setIdUserRole(int idUserRole) {
        this.idUserRole = idUserRole;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public void setUsers(List<Users> users) {
        this.users = users;
    }

}

Here is my Controller:这是我的控制器:

@RequestMapping("/login")
    public String login() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        
        if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
            return "login";
        }
        
        return "redirect:/login";
        
    }
    
    @RequestMapping("/logout")
    public String logout() {
        
        return "login";
        
    }
    
    @GetMapping
    public String login(@RequestParam(value = "error", defaultValue = "false") boolean loginError) {
        if (loginError) {
            return "error-404";
            }
        return "login";
        
    }
    
    @RequestMapping("/admin/home")
public String loginAdmin(Model model) {
    
    System.out.println("From Admin Controller");
    return "/admin/home";
}

@RequestMapping("/user/home")
public String loginUser(Model model) {
    
    System.out.println("From User Controller");
    
    return "/user/home";
}

Here is my WebSecurityConfiguration File:这是我的 WebSecurityConfiguration 文件:

package com.myproject.configure;

import org.springframework.beans.factory.annotation.Autowired;
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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.recruitmentmanagement.service.CustomUserDetailsService;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserDetailsService userDetailsService;
    
    @Autowired
    private CustomLoginSuccessHandler successHandler;
    
    
    
    @Bean
    public PasswordEncoder  passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
        .authorizeRequests()
        .antMatchers("/login","/registration", "/process_registration", "/userhome", "/landing", "/order", "/jobdetails/**").permitAll()
        .antMatchers("/user/**").hasAnyAuthority("USER", "ADMIN")
        .antMatchers("/admin/**").hasAnyAuthority("ADMIN")
        .anyRequest().authenticated()
        .and()
        .csrf().disable().formLogin()
        .loginPage("/login")
        .failureUrl("/login?error=true")
        .successHandler(successHandler)
        .usernameParameter("userName")
        .passwordParameter("password")
    .and()
    .logout()
    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
    .logoutSuccessUrl("/login").and()
    .exceptionHandling()
    .accessDeniedPage("/access-denied");
        
    }
    
    @Bean
    public LogoutSuccessHandler logoutSuccessHandler() {
        return new CustomLogoutSuccessHandler();
    }

    @Override
    public void configure(WebSecurity webSecurity) throws Exception {
        webSecurity.ignoring().antMatchers("/webjars/**",
                                            "/css/**", 
                                            "/js/**",
                                            "/images/**",
                                            "/node_modules/**",
                                            "/bower_components/**");
    }

    
    @Bean
    public DaoAuthenticationProvider authProvider() throws Exception {
        
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setPasswordEncoder(passwordEncoder());
        authenticationProvider.setUserDetailsService(userDetailsService);
        return authenticationProvider;
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        System.out.println("WebSecurityConfig -- " + authProvider().toString());
        auth.authenticationProvider(authProvider());
    }
    
}

Consider using official Spring Security model考虑使用官方 Spring Security 模型

So everything would be done for you所以一切都会为你做的

You could specify there roles and permissions for certain pages您可以为某些页面指定角色和权限

Ok so first off, you'll have to extend AuthenticationSuccessHandler, and your handle method should look something like this好的,首先,您必须扩展 AuthenticationSuccessHandler,并且您的句柄方法应如下所示

@Component
public class CustomSuccessHandler implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {

        String redirectUrl = determineTargetUrl(authentication);

        if (redirectUrl == null) {
            throw new SomeException();
        }

        new DefaultRedirectStrategy().sendRedirect(request, response, redirectUrl);
    }
}

At this point the url 'login?error=true' is reduntant.此时 url 'login?error=true' 是多余的。 You can safely remove it from the defineTargeUrl since you defined in the failure login url within the WebSecurityConfig class.您可以安全地从 defineTargeUrl 中删除它,因为您是在 WebSecurityConfig 类中的失败登录 url 中定义的。

With this said the controller should look so like this有了这个说控制器应该看起来像这样

@Controller
@RequestMapping
public class TestController {

    ...
}

I couldn't see the top of your controller class so make sure you've got both of those annotations.我看不到您的控制器类的顶部,因此请确保您已获得这两个注释。 Also be careful when defining the following conditions定义以下条件时也要小心

hasAnyAuthority("USER", "ADMIN")

and

roleName.contains("ADMIN")

You must use the 'equals' inside the redirect class it might cause ambiguities您必须在重定向类中使用“equals”,这可能会导致歧义

Actually i was getting only [USER] as authorities, its i found when i print authentication.getAuthorities();实际上,我只获得了 [USER] 作为权限,这是我在打印 authentication.getAuthorities() 时发现的; from my SuccessHandler class.来自我的 SuccessHandler 课程。 And when i check my authProvider() function from WebSecurity class where my users authorities provided by my CustomUserDetailsService.当我从 WebSecurity 类检查我的 authProvider() 函数时,我的用户权限由我的 CustomUserDetailsS​​ervice 提供。 I check my CustomUserDetailsService class and I found following :我检查了我的 CustomUserDetailsS​​ervice 类,发现以下内容:

package com.myproject.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
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.Service;

import com.recruitmentmanagement.entities.Users;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    UsersService usersService;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        
        final Users users = usersService.getUsersByUsers(username);
        
        if (users == null) {

            throw new UsernameNotFoundException("User not found !!!");              
        }

        UserDetails userDetails = User.withUsername(users.getUserName()).password(users.getPassword()).authorities("USER").build(); 
        
        
        
        return userDetails;

    }

}

Then i change my code and here is my final CustomUserDetailService class然后我更改我的代码,这是我的最终 CustomUserDetailService 类

package com.myproject.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
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.Service;

import com.recruitmentmanagement.entities.Users;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    UsersService usersService;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        
        final Users users = usersService.getUsersByUsers(username);
        
        if (users == null) {

            throw new UsernameNotFoundException("User not found !!!");              
        }

        UserDetails userDetails = User.withUsername(users.getUserName()).password(users.getPassword()).authorities(users.getUserRole().getRoleName()).build();  
        
        
        
        return userDetails;

    }

}

Thank you to everyone who tries to help me.感谢所有试图帮助我的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM