spring - 使用 RESTful 登录 API 验证我的 Spring Boot 应用程序

标签 spring rest api spring-boot spring-security

我正在开发一个 Spring Boot 应用程序,该应用程序根据端点登录 API 对用户进行身份验证,即:
我们通常直接检查数据库中保存的用户名和密码。但是这次凭证是在另一个程序员开发的登录端点 API 中。
我的 Spring Boot 应用程序需要针对该登录 api 的用户身份验证“登录表单”。在授予对应用程序的访问权限之前。换句话说,用户名和密码来自未保存在数据库中的 API!那是别人已经开发的登录api。任何的想法?我以前没有这样做过!登录 API 是:

POST: domain/authenticate/user
body 是:
{    "username" : "user",  
     "password" : "test"
}
回应是:
{
"customer": {
    "id": 62948,
    "email": "test@test.com.au",
    "givenName": "A",
    "familyName": "OB",
    "user": {
        "id": 63158,
        "version": 1,
        "email": "adamo@test.com.au",
        "password": "113b984921197350abfedb0a30f6e215beeda6c718e36559f48eae946664b405c77bc6bab222fe8d3191f82925921438b6566dda76613aa6cd4416e5d9ae51c8",
        "givenName": "A",
        "familyName": "OB",
     },
    "vehicles": [
        {
            "id": 79369,
            "version": 0,
            "country": "Australia"
            },
            "newState": null,
        }
    ],
    "fundingSources": [
        {
            "@class": "au.com.test.test",
            "id": 54795,
            "version": 0,
        }
    ],
    
    "citySuburb": null,
}
}

最佳答案

首先,您需要创建一个客户端来使用您的 rest api 进行身份验证:

@Service
public class AuthService {

    @Bean
    public RestTemplate authRestTemplate() {
        return new RestTemplateBuilder().rootUri("http://domain/authenticate").build();
    }

    public Customer authenticate(MultiValueMap<String, String> request) {
        return authRestTemplate().postForObject("/user", request, Customer.class);
    }

    public MultiValueMap<String, String> createRequest(String username, String password) {
        MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
        request.add("username", username);
        request.add("password", password);
        return request;
    }

}

然后您必须创建一个组件或服务来使用该客户端:
@Service
public class AuthenticationService implements AuthenticationProvider {

private AuthService authService;

@Autowired
public void setAuthService(AuthService authService) {
    this.authService = authService;
}

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    String username = authentication.getName();
    String password = authentication.getCredentials().toString();

    Customer customer = authService.authenticate(authService.createRequest(username, password));
    if (customer != null) {
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
//here you need to store your Customer object to use it anywhere while the user is logged in
// take a look on the edit
        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        return new UsernamePasswordAuthenticationToken(username, password, grantedAuthorities);
    }
    throw new AuthenticationServiceException("Invalid credentials.");

}

@Override
public boolean supports(Class<?> authentication) {
    return authentication.equals(UsernamePasswordAuthenticationToken.class);
}

}

最后,您需要使用自定义身份验证服务进行基本安全配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration implements WebMvcConfigurer {

    private AuthenticationService authenticationService;

    @Autowired
    public void setAuthenticationService(AuthenticationService authenticationService) {
        this.authenticationService = authenticationService;
    }

    @Bean
    public WebSecurityConfigurerAdapter webSecurityConfig() {
        return new WebSecurityConfigurerAdapter() {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                        .csrf()
                        .disable()
                        .authorizeRequests()
                        .antMatchers("/webjars/**").permitAll()
                        .anyRequest().authenticated()
                        .and()
                        .formLogin()
                        .loginPage("/login")
                        .permitAll()
                        .and()
                        .logout()
                        .permitAll();
            }

            @Override
            protected void configure(AuthenticationManagerBuilder builder) throws Exception {
                builder.authenticationProvider(authenticationService);
            }

        };

        }
}

您需要在 Customer 中创建登录 api 响应的 DTO对象并考虑如何将信息存储到 GrantedAuthority 的列表中

您可以使用许多其他选项,但这对我来说很容易。

编辑:这里只是一个想法如何为您的身份验证 api 实现 GrantedAuthority:

首先,您需要一个实现接口(interface)并存储整个 json 的对象:
public class CustomerGrantedAuthority implements org.springframework.security.core.GrantedAuthority {

    private String customerJson;

    public CustomerGrantedAuthority(String customerJson){
        this.customerJson = customerJson;
    }

    @Override
    public String getAuthority() {
        return customerJson;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CustomerGrantedAuthority that = (CustomerGrantedAuthority) o;
        return java.util.Objects.equals(customerJson, that.customerJson);
    }

    @Override
    public int hashCode() {
        return java.util.Objects.hash(customerJson);
    }

    @Override
    public String toString() {
        return this.customerJson;
    }

}

更好的解决方案是创建一个对象并将其存储为一个对象,而不是作为一个字符串,而只是为了示例它是一个字符串。

然后你需要更改AuthenticationService在您访问身份验证 api 的代码中:
String customer = new RestTemplate().postForObject("http://domain/authenticate/user", createRequest(username, password), String.class);
    if (customer != null) {
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
    grantedAuthorities.add(new CustomerGrantedAuthority(new ObjectMapper().writeValueAsString(customer)));
        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        return new UsernamePasswordAuthenticationToken(username, password, grantedAuthorities);
    }
    throw new AuthenticationServiceException("Invalid credentials.");

public MultiValueMap<String, String> createRequest(String username, String password) {
            MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
            request.add("username", username);
            request.add("password", password);
            return request;
        }

这取决于您希望在应用程序中访问用户信息的位置和方式,但只是为了查看它是否有效,您可以使用简单的 RestController 进行测试,当用户登录时应该可以看到:
@RestController
public class TestController {

    @GetMapping(value = "/auth")
    public ResponseEntity getAuth() {
        Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
        CustomerGrantedAuthority customer = (CustomerGrantedAuthority) authorities.stream().findFirst().orElse(null);
        return customer != null ? ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(customer.getAuthority()) : ResponseEntity.notFound().build();
    }

}

对不起,很长的帖子,如果有拼写错误,我深表歉意。正如我所说,这只是我的意见,还有很多其他的解决方案。

关于spring - 使用 RESTful 登录 API 验证我的 Spring Boot 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55135304/

相关文章:

c# - 如何使用注释覆盖同一方法上的 Web api 路由

java - 如何正确向Spring Restful WebService提交特殊字符?

java - Spring Web Flow——流程被重置

java - Hibernate 在不同线程上运行时不必要地创建新实体

java - 我需要为 JDK 1.6 下载什么 Jersey 版本?

ios - 我的 iOS 音乐应用程序的歌词 api

java - 在 spring mvc 中将 javascript 值传递给 Controller

javascript - Backbone JS - 在 REST 接口(interface)中删除模型

python - 在不打开浏览器Python的情况下打开授权URL

api - 是否还有免费的 CDDB 数据库?