Saya memiliki rest api di mana saya mengautentikasi menggunakan keamanan musim semi Otorisasi Dasar di mana klien mengirimkan nama pengguna dan kata sandi untuk setiap permintaan. Sekarang, saya ingin mengimplementasikan otentikasi berbasis token di mana saya akan mengirim token di header respons ketika pengguna diautentikasi pada awalnya. Untuk permintaan lebih lanjut, klien dapat menyertakan token itu di header yang akan digunakan untuk mengotentikasi pengguna ke sumber daya. Saya memiliki dua penyedia otentikasi tokenAuthenticationProvider dan daoAuthenticationProvider
@Component
public class TokenAuthenticationProvider implements AuthenticationProvider {
@Autowired
private TokenAuthentcationService service;
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
final HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
final String token = request.getHeader(Constants.AUTH_HEADER_NAME);
final Token tokenObj = this.service.getToken(token);
final AuthenticationToken authToken = new AuthenticationToken(tokenObj);
return authToken;
}
@Override
public boolean supports(final Class<?> authentication) {
return AuthenticationToken.class.isAssignableFrom(authentication);
}
}
Dan di daoAuthenticationProvider saya mengatur userDetailsService khusus dan mengautentikasi terhadap detail login pengguna dengan mengambilnya dari database (yang berfungsi dengan baik selama nama pengguna dan kata sandi dilewatkan menggunakan Authorization:Basic bGllQXBpVXNlcjogN21wXidMQjRdTURtR04pag== sebagai header)
Tetapi ketika saya memasukkan token di header menggunakan X-AUTH-TOKEN (yang merupakan Constants.AUTH_HEADER_NAME), tokenAuthenticationProvider tidak dipanggil. Saya mendapatkan kesalahan sebagai
{"timestamp":1487626368308,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/find"}
Dan inilah cara saya menambahkan penyedia otentikasi.
@Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
final UsernamePasswordAuthenticationProvider daoProvider = new
UsernamePasswordAuthenticationProvider(this.service, this.passwordEncoder());
auth.authenticationProvider(this.tokenAuthenticationProvider);
auth.authenticationProvider(daoProvider);
}
Tolong sarankan bagaimana saya bisa menerapkan otentikasi berbasis Token tanpa merusak perilaku keamanan musim semi saat ini.
Berikut ini adalah bagaimana saya bisa mengimplementasikan autentikasi berbasis token dan autentikasi dasar
SpringSecurityConfig.java
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(this.participantService).passwordEncoder(this.passwordEncoder());
}
@Override
protected void configure(final HttpSecurity http) throws Exception
{
//Implementing Token based authentication in this filter
final TokenAuthenticationFilter tokenFilter = new TokenAuthenticationFilter();
http.addFilterBefore(tokenFilter, BasicAuthenticationFilter.class);
//Creating token when basic authentication is successful and the same token can be used to authenticate for further requests
final CustomBasicAuthenticationFilter customBasicAuthFilter = new CustomBasicAuthenticationFilter(this.authenticationManager() );
http.addFilter(customBasicAuthFilter);
}
}
TokenAuthenticationFilter.java
public class TokenAuthenticationFilter extends GenericFilterBean
{
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException
{
final HttpServletRequest httpRequest = (HttpServletRequest)request;
//extract token from header
final String accessToken = httpRequest.getHeader("header-name");
if (null != accessToken) {
//get and check whether token is valid ( from DB or file wherever you are storing the token)
//Populate SecurityContextHolder by fetching relevant information using token
final User user = new User(
"username",
"password",
true,
true,
true,
true,
authorities);
final UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}
CustomBasicAuthenticationFilter.java
@Component
public class CustomBasicAuthenticationFilter extends BasicAuthenticationFilter {
@Autowired
public CustomBasicAuthenticationFilter(final AuthenticationManager authenticationManager) {
super(authenticationManager);
}
@Override
protected void onSuccessfulAuthentication(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response, final Authentication authResult) {
//Generate Token
//Save the token for the logged in user
//send token in the response
response.setHeader("header-name" , "token");
}
}
Karena CustomBasicAuthenticationFilter kami telah dikonfigurasi dan ditambahkan sebagai filter ke keamanan pegas,
Setiap kali otentikasi dasar berhasil, permintaan akan diarahkan ke onSuccessfulAuthentication di mana kami mengatur token dan mengirimkannya sebagai respons dengan beberapa header "header-name".
Jika "header-name" dikirim untuk permintaan lebih lanjut, maka permintaan akan melalui TokenAuthenticationFilter terlebih dahulu sebelum mencoba untuk mencoba Otentikasi Dasar.
Anda dapat mencoba mengatur token AuthenticationToken
khusus Anda dalam filter autentikasi Anda, misalnya:
public class AuthenticationFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final String authTokenHeader = ((HttpServletRequest)request).getHeader(Constants.AUTH_HEADER_NAME);
if (authTokenHeader != null) {
SecurityContextHolder.getContext().setAuthentication(createAuthenticationToken(authTokenHeader));
}
chain.doFilter( request, response );
}
}