Spring Security-401未经授权的访问 [英] Spring Security - 401 Unauthorized access
问题描述
我已经创建了一个将数据发送到我的后端的表单,该表单将其持久化到数据库中
I've created a form that sends the data to my backend, which persists it into the database
只要我的antMatcher上具有.permitAll(),此方法就很好用,但是当我尝试保护它以使只有管理员可以进行此调用时(数据库中的管理员角色是ROLE_ADMIN),它将返回401未经授权的访问没有消息.我已经尝试过
This works well as long as I have .permitAll() on my antMatcher, but when I try to secure it so that only admins can make that call (admin role in the DB is ROLE_ADMIN), it returns a 401 Unauthorized Access with no message. I've tried
- .hasRole("ADMIN"))
- .hasRole("ROLE_ADMIN")
- .hasAuthority("ADMIN")
- .hasAuthority("ROLE_ADMIN")
它们都不起作用.
我的请求看起来像这样(张贴标题):
My request looks like this (posting for the headers):
我的SecurityConfig类:
My SecurityConfig class:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean(BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/api/book/**")
.permitAll()
.antMatchers("/api/author/**")
// .permitAll()
.hasAnyRole("ROLE_ADMIN", "ADMIN", "ROLE_USER", "USER", "ROLE_ROLE_ADMIN",
"ROLE_ROLE_USER")
.anyRequest()
.authenticated();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
我的UserDetailsServiceImpl类:
My UserDetailsServiceImpl class:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String email)
throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
return UserDetailsImpl.create(user);
}
@Transactional
public UserDetails loadUserById(Integer id) {
User user = userRepository.findById(id).orElseThrow(
() -> new UsernameNotFoundException("User not found with id: " + id)
);
return UserDetailsImpl.create(user);
}
}
我的JwtAuthenticationEntryPoint类:
My JwtAuthenticationEntryPoint class:
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
logger.error("Unauthorized access. Message:", e.getMessage());
httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
}
}
我的JwtAuthenticationFilter:
My JwtAuthenticationFilter:
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider tokenProvider;
@Autowired
private UserDetailsServiceImpl userDetailsService;
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse
httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(httpServletRequest);
if(StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Integer userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = userDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new
UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new
WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
}
} catch (Exception e) {
logger.error("Could not set user authentication in security context", e);
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
已正确检查JWT令牌的有效性.那不是手头的问题.感谢您的帮助.
The JWT Token's validity is properly checked. That's not the issue at hand. Any help is appreciated.
添加了UserDetailsImpl的实现:
Added implementation of UserDetailsImpl:
public class UserDetailsImpl implements UserDetails {
private Integer id;
@JsonIgnore
private String email;
private String name;
@JsonIgnore
private String password;
private boolean isAdmin;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsImpl(Integer id, String email, String name, String
password, boolean isAdmin, Collection<? extends GrantedAuthority>
authorities) {
this.id = id;
this.name = name;
this.email = email;
this.password = password;
this.authorities = authorities;
this.isAdmin = isAdmin;
}
public static UserDetailsImpl create(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream().map(role ->
new SimpleGrantedAuthority(role.getName().name())
).collect(Collectors.toList());
boolean isAdmin = false;
for(Role role: user.getRoles()) {
if(RoleName.ROLE_ADMIN.equals(role.getName())) {
isAdmin = true;
}
}
return new UserDetailsImpl(
user.getId(),
user.getEmail(),
user.getName(),
user.getPassword(),
isAdmin,
authorities
);
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String getUsername() {
return email;
}
@Override
public String getPassword() {
return password;
}
public boolean isAdmin() {
return isAdmin;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserDetailsImpl that = (UserDetailsImpl) o;
return Objects.equals(id, that.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
添加了此命令以检查在UserDetailsImpl.create(user)调用之后是否存在权限:
Added this to check if the authorities are present after UserDetailsImpl.create(user) call:
输出:
AuthenticationController的登录部分:
Login part of the AuthenticationController:
推荐答案
我看到您没有更新 SecurityContextHolder
.无法发表评论,所以我在这里写了.
I see that you are not updating the SecurityContextHolder
. Unable to put it in a comment, so I wrote it here.
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest))
SecurityContextHolder.getContext().setAuthentication(authentication); //this seems missing
这篇关于Spring Security-401未经授权的访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!