因此,我有两种不同类型的用户,一个具有 USER 角色的 User 实体和一个具有 HOST 角色的 HOST 实体,并且角色具有相应的权限。我创建了一个实现 UserDetails 的 UserPrincipal,我在其中覆盖了该getAuthorities()
方法并添加了一个 simpleGrantedAuthority。我将角色和权限创建为枚举。这是ApplicationUserPermission
指定权限的枚举。
public enum ApplicationUserPermission {
USER_READ("user:read"),
USER_WRITE("user:write"),
HOST_READ("host:read"),
HOST_WRITE("host:write"),
APARTMENT_READ("apartment:read"),
APARTMENT_WRITE("apartment:write");
private final String permission;
ApplicationUserPermission(String permission) {
this.permission = permission;
}
public String getPermission() {
return permission;
}
然后我ApplicationUserRole
将这些权限设置为两个不同的角色:用户和主机。
public enum ApplicationUserRole {
USER(Sets.newHashSet(USER_READ, USER_WRITE, APARTMENT_READ)),
HOST(Sets.newHashSet(HOST_READ, HOST_WRITE, APARTMENT_READ, APARTMENT_WRITE));
private final Set<ApplicationUserPermission> permissions;
ApplicationUserRole(Set<ApplicationUserPermission> permissions) {
this.permissions = permissions;
}
public Set<ApplicationUserPermission> getPermissions() {
return permissions;
}
然后我有UserPrincipal
那个实现UserDetails
并设置用户实体的权限
public class UserPrincipal implements UserDetails {
private final User user;
public UserPrincipal(User user) {
super();
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singleton(new SimpleGrantedAuthority("ROLE_"+USER.name()));
}
然后我有我的自定义UserDetailsService
实现UserDetailsService
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Autowired
private HostRepository hostRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
String lastDigits = username.substring(username.length() - 3);
User user;
Host host;
if (username.contains("@")) {
host = hostRepository.findByEmail(username);
if (host == null) {
throw new UsernameNotFoundException("Server 404");
}
return new HostPrincipal(host);
}
user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Server 404");
}
return new UserPrincipal(user);
}
这是我的ApplicationSecurityConfig.java
:
@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Qualifier("myUserDetailsService")
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
@Bean
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().disable()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and() // check if user exist in database and create a token for specific user
.addFilter(new JwtUsernameAndPasswordAuthAuthenticationFilter(authenticationManager()))
.addFilterAfter(new JwtTokenVerifier(), JwtUsernameAndPasswordAuthAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/", "/login", "/createHost", "/createUser", "/getAllApartments").permitAll()
.antMatchers("/users/**").hasRole("USER")
.antMatchers("/hosts/**").hasRole(HOST.name()).anyRequest().authenticated()
.httpBasic().authenticationEntryPoint(authenticationEntryPoint);
}
这是我的JwtUsernameAndPasswordAuthFilter.java
:
public class JwtUsernameAndPasswordAuthAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private static final Logger logger = LoggerFactory.
getLogger(JwtUsernameAndPasswordAuthAuthenticationFilter.class);
private final AuthenticationManager authenticationManager;
public JwtUsernameAndPasswordAuthAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
UsernamePasswordAuthenticationRequest authenticationRequest =
new ObjectMapper().readValue(request.getInputStream(),
UsernamePasswordAuthenticationRequest.class);
Authentication authentication = new UsernamePasswordAuthenticationToken(
authenticationRequest.getUsername(),
authenticationRequest.getPassword()
);
authenticationManager.authenticate(authentication);
return authentication;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
logger.info("Auth result: {}", authResult);
logger.info("Authorities: {}", authResult.getAuthorities());
String key = "securesecuresecuresecuresecuresecuresecuresecuresecuresecuresecure";
String token = Jwts.builder()
.setSubject(authResult.getName())
.claim("authorities", authResult.getAuthorities())
.setIssuedAt(Date.valueOf(LocalDate.now().plusWeeks(2)))
.signWith(Keys.hmacShaKeyFor(key.getBytes()))
.compact();
String tokenAsJson = new JSONObject()
.put("token", token)
.toString();
response.addHeader("Authorization", "Bearer " + token);
response.setContentType("application/json");
response.getWriter().write(tokenAsJson);
}
编辑:这是我的授权过滤器
public class JwtTokenVerifier extends BasicAuthenticationFilter {
public JwtTokenVerifier(AuthenticationManager authenticationManager){
super(authenticationManager);
}
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader("Authorization");
if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
String secretKey = "securesecuresecuresecuresecuresecuresecuresecuresecuresecuresecure";
String token = authorizationHeader.replace("Bearer ", "");
try {
Jws<Claims> claimsJws = Jwts.parser().
setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes())).parseClaimsJws(token);
Claims body = claimsJws.getBody();
String username = body.getSubject();
var authorities = (List<Map<String, String>>) body.get("authorities");
Set<SimpleGrantedAuthority> simpleGrantedAuthoritySet = authorities.stream()
.map(m -> new SimpleGrantedAuthority(m.get("authority"))).collect(Collectors.toSet());
Authentication authentication = new UsernamePasswordAuthenticationToken(username,
null, simpleGrantedAuthoritySet);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (JwtException e) {
throw new IllegalStateException(String.format("Token %s cannot be trusted", token));
}
filterChain.doFilter(request, response);
}
}
authResult.getAuthorities()
返回空 []。如果我在以用户身份登录后尝试访问“/users/**”,则会返回 403 Forbidden。