我正在使用 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。
任何人都可以解决这个问题吗?
好吧我自己解决了。
首先,我在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");
})
...
感谢和问候