简体   繁体   English

spring 安全性中的不透明令牌实现

[英]Opaque Token Implementation in spring security

im trying to create a secured spring rest api for the security i want to use opaque token stored in the database so that if the client query on the api with a bearer token. im trying to create a secured spring rest api for the security i want to use opaque token stored in the database so that if the client query on the api with a bearer token. the server will check on the database if the token exist if the token is valid and get the user and the privilege and check if the user have the authority to do the request.如果令牌有效,服务器将检查数据库是否存在令牌并获取用户和权限,并检查用户是否有权执行请求。 i've done some research on the net but didn't found result that can be understood by a beginner.我在网上做了一些研究,但没有找到初学者可以理解的结果。 how can i implement this.我该如何实现这一点。 method 1 found method 2 i have found this two methods but i dont know where too implements the database verification and validation 方法1找到方法2我找到了这两种方法但我不知道在哪里实现数据库验证和验证

after a lot of research i've found this and it is working first i've created a Authorization filter like this:经过大量研究后,我发现了这一点,并且它首先起作用,我创建了一个这样的授权过滤器:

package com.example.bda_test_11.security;

import com.example.bda_test_11.model.BdaUser;
import com.example.bda_test_11.model.Token;
import com.example.bda_test_11.repository.TokenRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
public class AuthorizationFilter extends BasicAuthenticationFilter {
    private final TokenRepository tokenRepository;
    public AuthorizationFilter(AuthenticationManager authenticationManager,TokenRepository tokenRepository) {
        super(authenticationManager);
        this.tokenRepository = tokenRepository;
    }
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String tokenCode = request.getHeader(HttpHeaders.AUTHORIZATION);
        log.info(tokenCode);
        if(tokenCode == null ) {
            filterChain.doFilter(request,response);
            return;
        }
        Token token = tokenRepository.findByCode(tokenCode).orElse(null);
        if (token == null) {
            
            filterChain.doFilter(request,response);
            return;
        }
        BdaUser user = token.getUser();
        UsernamePasswordAuthenticationToken userToken = new UsernamePasswordAuthenticationToken(user.getLogin(),null,user.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(userToken);
        filterChain.doFilter(request,response);
    }
}

and a UsernamePasswordAuthenticationFilter like this和这样的 UsernamePasswordAuthenticationFilter

package com.example.bda_test_11.security;

import com.example.bda_test_11.security.domain.LoginCredentials;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
@Slf4j
public class JsonObjectAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final ObjectMapper objectMapper = new ObjectMapper();



    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
        try{


            BufferedReader reader = request.getReader();
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line=reader.readLine())!=null){
                stringBuilder.append(line);
            }
            LoginCredentials authRequest = objectMapper.readValue(stringBuilder.toString(),LoginCredentials.class);
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                    authRequest.getLogin(),
                    authRequest.getPassword()
            );
            setDetails(request,token);
            log.info(token.toString());
            return this.getAuthenticationManager().authenticate(token);
        } catch (IOException e){
            throw new RuntimeException(e);
        }
    }
}

if the connection is successful we generate a token like:如果连接成功,我们会生成一个令牌,如:

package com.example.bda_test_11.security;

import com.example.bda_test_11.model.BdaUser;
import com.example.bda_test_11.model.Token;
import com.example.bda_test_11.repository.TokenRepository;
import com.example.bda_test_11.service.BdaUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j @Component
public class AuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
    private final TokenRepository tokenRepository;
    private final BdaUserService userService;

    @Autowired
    public AuthSuccessHandler(TokenRepository tokenRepository, BdaUserService userService) {
        this.tokenRepository = tokenRepository;
        this.userService = userService;
    }
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        UserDetails principal = (UserDetails) authentication.getPrincipal();
        BdaUser user = userService.findByLogin(principal.getUsername());
        Token token = new Token(user);
        tokenRepository.save(token);
        log.info(token.getCode());
        response.addHeader("Authorization",token.getCode());
        response.addHeader("Content-Type","application/json");
        response.getWriter().write("{\"token\":"+token.getCode()+",\"login\":"+user.getLogin());
    }
}

and then ive configured the filterChain bean like this然后我像这样配置了filterChain bean

package com.example.bda_test_11.security;

import com.example.bda_test_11.repository.TokenRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;

@Configuration
public class BdaSecurity {
    private final AuthenticationManager authenticationManager;
    private final AuthSuccessHandler authSuccessHandler;
    private final TokenRepository tokenRepository;

    @Autowired
    public BdaSecurity(AuthenticationManager authenticationManager, AuthSuccessHandler authSuccessHandler, TokenRepository tokenRepository) {
        this.authenticationManager = authenticationManager;
        this.authSuccessHandler = authSuccessHandler;
        this.tokenRepository = tokenRepository;
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .authorizeHttpRequests((auth)->{

                    try {
                        auth
                                .antMatchers("/api/admin").hasAuthority("ADMIN")
                                .antMatchers("/api/user").hasAuthority("USER")
                                .anyRequest().permitAll()
                                .and()
                                .sessionManagement()
                                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                                .and()
                                .addFilter(authenticationFilter())
                                .addFilter(new AuthorizationFilter(authenticationManager,tokenRepository))
                                .exceptionHandling()
                                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                })
                .httpBasic(Customizer.withDefaults());
        return http.build();
    }
    @Bean
    public JsonObjectAuthenticationFilter authenticationFilter() {
        JsonObjectAuthenticationFilter filter = new JsonObjectAuthenticationFilter();
        filter.setAuthenticationSuccessHandler(authSuccessHandler);
        filter.setAuthenticationManager(authenticationManager);
        return filter;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM