使用 Spring security 的角色和权限的问题

问题描述 投票:0回答:1

我正在使用 Spring Security 3。 我的目标是根据特定用户的角色和权限授予特定操作(控制器方法)。

ROLE_ADMIN -> 创建、读取、更新和删除 ROLE_USER -> 读取并更新。

当我注册用户时,它会作为用户对象保存到数据库中,并且密码加密,没有任何问题。但是,当我使用

UserController
并使用 Postman 进行基本身份验证时,它显示状态 200 OK,但不是预期的 json 输出。然后,当我使用 Google Chrome 点击相同的网址时,它会显示 Whitelabel 错误页面,状态为 404 NOT FOUND。

这是我的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 按

http://localhost:8081/user/findproduct?productid=1
代表
UserController
时,登录页面会重定向。然后,如果我点击成功注册并保存到数据库的用户名/密码凭据,则会显示 Whitelabel 错误页面,状态为 404 NOT FOUND。

任何人都可以解决这个问题吗?

java spring-security roles user-permissions
1个回答
1
投票

好吧我自己解决了。

首先,我在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");
                   })
...

感谢和问候

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.