Spring Security 使用Roles的问题和使用Spring安全性的问题

h5qlskok  于 2023-10-20  发布在  Spring
关注(0)|答案(1)|浏览(199)

我使用的是Spring Security 3我的目标是基于角色和权限授予特定用户特定的操作(控制器方法)。
ROLE_ADMIN ->创建、读取、更新和删除ROLE_USER ->读取和更新。
当我注册一个用户时,它会作为一个用户对象保存到一个数据库中,密码加密,没有问题。但是当我使用UserController和Postman的基本身份验证来访问控制器API时,它显示状态200 OK,但不是预期的JSON输出。然后在面对,当我击中相同的网址与谷歌Chrome,它是显示白标签错误页面与状态404未找到。
这里是我的SecurityConfig.java

@Configuration
//@Import({GsonConfig.class}) 
@EnableMethodSecurity 
@EnableWebSecurity(debug = true)
public class SecurityConfig {
    
    @Autowired
    ProductUserRepository productuserrepo;

    @Bean
    public PasswordEncoder encoder() { 
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    public UserDetailsService userDetailsService() {
        return username -> productuserrepo.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("User not found"));
    }
      
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
      return http.csrf(csrf -> csrf.disable()) 
                 .cors(cors -> cors.disable())
                 .authorizeHttpRequests(a -> {
                                           a.requestMatchers("/auth/**").permitAll();
                                           a.anyRequest().authenticated();   
                   })
                   .formLogin(login -> {
                                login.loginProcessingUrl("/login")
                                     .failureForwardUrl("/loginfailure");
                   })
                   .logout(logout ->{
                            logout.logoutUrl("/logout")
                                  .deleteCookies("JSESSIONID")
                                  .invalidateHttpSession(false)
                                  .logoutSuccessUrl("/successlogout")
                                  .logoutSuccessHandler((request, response, authentication) -> SecurityContextHolder.clearContext());
                    }) 
                   .authenticationManager(authManager()) 
                   .build();
    } 
    
    @Bean
    public AuthenticationManager authManager(){
        DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
        daoProvider.setUserDetailsService(userDetailsService());
        daoProvider.setPasswordEncoder(encoder());
        return new ProviderManager(daoProvider);
    }

}

这是我的Role.java [使用List<SimpleGrantedAuthority>获取权限列表]

@RequiredArgsConstructor
public enum Role {

    USER(Set.of(USER_READ,USER_UPDATE)),
      
    ADMIN(Set.of(ADMIN_READ,ADMIN_UPDATE,ADMIN_DELETE,ADMIN_CREATE,
                   USER_READ,USER_UPDATE));
     
    @Getter
    private final Set<Permission> permissions;
    
    public  List<SimpleGrantedAuthority> getAuthorities() {
            List<SimpleGrantedAuthority> authorities = getPermissions().stream()
                                                                        .map(permission -> new SimpleGrantedAuthority(permission.getPermission()))
                                                                        .collect(Collectors.toList());
            authorities.add(new SimpleGrantedAuthority("ROLE_" + this.name()));
            return authorities;
    }
}

这里是我的Permission.java

public enum Permission {

    ADMIN_READ("admin:read"),
    ADMIN_UPDATE("admin:update"),
    ADMIN_CREATE("admin:create"),
    ADMIN_DELETE("admin:delete"),
    USER_READ("user:read"),
    USER_UPDATE("user:update");

    @Getter
    private final String permission;
}

最后这里是我的用户控制器读取资源

@RestController
@RequestMapping("/user")
@PreAuthorize("hasAnyRole('USER','ADMIN')")
public class UserController {
    
    @PreAuthorize("hasAnyAuthority('admin:read','user:read')")
    @GetMapping(value = "/findproduct",produces = MediaType.APPLICATION_JSON_VALUE,
            headers = "Accept=application/json",consumes = MediaType.APPLICATION_JSON_VALUE)
    public Product findproductbyid(@RequestParam("productid")int productid) {
        System.out.println("inside findproduct method");
        return prodrepo.findById(productid).get(); 
    }
}

和我的AuthController注册:

@RestController
@RequestMapping("/auth")
public class AuthController {

@Autowired
ProductUserRepository produserrepo;

@Autowired
PasswordEncoder pwd_encoder; 

@Autowired
Gson gson;

@PostMapping(value = "/register",produces = MediaType.APPLICATION_JSON_VALUE,
        headers = "Accept=application/json",consumes = MediaType.APPLICATION_JSON_VALUE)
public String register(@RequestBody ProductUserModel user) {
    
    if (produserrepo.existsByUsername(user.getUsername())) {  
        return user.getUsername() + " already taken";
    }else { 
        System.out.println(user.toString());
            user.setPassword(pwd_encoder.encode(user.getPassword()));  
            produserrepo.save(gson.fromJson(gson.toJson(user), ProductUser.class));
            return user.getUsername() + " succesfully registered";
    }
}

我唯一的问题是:当我使用Google Chrome为UserController点击http://localhost:8081/user/findproduct?productid=1时,登录页面重定向。然后,如果我击中用户名/密码凭据,我成功地注册并保存到数据库,它显示白标签错误页面状态404未找到。
有没有人有办法解决这个问题?

yduiuuwa

yduiuuwa1#

好吧,我自己解决。
首先,我在AuthController中添加了登录方法

@GetMapping(value = "/login",produces = MediaType.APPLICATION_JSON_VALUE,
            headers = "Accept=application/json",consumes = MediaType.APPLICATION_JSON_VALUE)
    public void login(HttpServletRequest req,@RequestHeader(HttpHeaders.AUTHORIZATION) String authorization) {
        
        if (authorization != null && authorization.toLowerCase().startsWith("basic")) {
            // Authorization: Basic base64credentials
            String base64Credentials = authorization.substring("Basic".length()).trim();
            byte[] credDecoded = Base64.getDecoder().decode(base64Credentials); 
            String credentials = new String(credDecoded, StandardCharsets.UTF_8);
            // credentials = username:password
            final String[] values = credentials.split(":", 2);
            String username = values[0];
            String password = values[1];
            authenticateusercredentials(username, password, req);
        }else {
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            authenticateusercredentials(username, password, req);
        }
    }
     
    public void authenticateusercredentials(String username,String password,HttpServletRequest req) {
        UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(username, password);
        Authentication auth = authmanager.authenticate(authReq);
        SecurityContext sc = SecurityContextHolder.getContext();
        sc.setAuthentication(auth);
        HttpSession session = req.getSession(true);
        session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, sc);
    }

其次,我在安全配置类中将/login更改为auth/login

...

.formLogin(login -> {
                                login.loginProcessingUrl("/auth/login")
                                     .failureForwardUrl("/loginfailure");
                   })
...

谢意和真挚的问候

相关问题