0

因此,我有两种不同类型的用户,一个具有 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。

4

0 回答 0