1. 程式人生 > 實用技巧 >spring Security 不使用controller 實現登陸資訊檢驗返回配置 token的實現

spring Security 不使用controller 實現登陸資訊檢驗返回配置 token的實現

結構

1WebSecurityConfigurer extends WebSecurityConfigurerAdapter 主體配置加上 2 (AuthenticationTokenFilter extends BasicAuthenticationFilter)新增 filter 過濾登陸資訊 3在登陸成功和失敗的handler寫返回值

1WebSecurityConfigurer

 protected void configure(HttpSecurity http) {
        List<String> permitAll = authIgnoreConfig.getIgnoreUrls();
        permitAll.add(
"/actuator/**"); permitAll.add("/error"); permitAll.add("/v2/**"); permitAll.add(Constant.TOKEN_ENTRY_POINT_URL); String[] urls = permitAll.stream().distinct().toArray(String[]::new); ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests(); registry.antMatchers(urls).permitAll().anyRequest().authenticated()
//url裡的連結允許通過,其他的必須有附權才能通過 .and().csrf().disable(); http // 基於token,所以不需要session .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .headers().frameOptions().disable()//防止frame巢狀攻擊 .and() .formLogin() .loginProcessingUrl(Constant.TOKEN_ENTRY_POINT_URL)
//這裡寫的就是登陸的介面 重點 .successHandler(authenticationSuccessHandler()) //成功返回 重點 .failureHandler(authenticationFailureHandler())//失敗返回 重點 .and() .logout() .logoutUrl(Constant.TOKEN_LOGOUT_URL) .addLogoutHandler(logoutHandler()) .logoutSuccessUrl("/sys/logout") .permitAll() .and() .exceptionHandling() //錯誤處理 .authenticationEntryPoint(new TokenAuthenticationFailHandler()) .and() // 如果不用驗證碼,註釋這個過濾器即可 .addFilterBefore(new ValidateCodeFilter(redisTemplate,authenticationFailureHandler()),UsernamePasswordAuthenticationFilter.class) //校驗token過濾器 這裡相當於加了一個過濾器,如果不符合條件就攔截 如你的請求不帶token就攔截 重點 .addFilterBefore(new AuthenticationTokenFilter(authenticationManagerBean(),redisTemplate,customUserDetailsService), UsernamePasswordAuthenticationFilter.class); }

2AuthenticationTokenFilter 校驗所有連結是否有登陸的token 或者校驗登陸密碼資訊

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

/**   校驗配置   這只是個filter 自定義了一個filter 因為沒用session 取不出來
 * @Description //TODO $
 * @Date 22:23
 * @Author [email protected]
 **/
@Slf4j
public class AuthenticationTokenFilter extends BasicAuthenticationFilter {

    private RedisTemplate redisTemplate;
    private CustomUserDetailsService customUserDetailsService;
    private ObjectMapper objectMapper = new ObjectMapper();

    public AuthenticationTokenFilter(AuthenticationManager authenticationManager,RedisTemplate template,CustomUserDetailsService customUserDetailsService) {
        super(authenticationManager);
        this.redisTemplate = template;
        this.customUserDetailsService = customUserDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        String token = request.getHeader(Constant.TOKEN);
        if(StrUtil.isBlank(token) || StrUtil.equals(token,"null")){
            token = request.getParameter(Constant.TOKEN);
        }
         //如果沒有token就加token
        if(StrUtil.isNotBlank(token) && !StrUtil.equals(token,"null")){
            Object userId = redisTemplate.opsForValue().get(token);
            if(ObjectUtil.isNull(userId)){
                writer(response,"無效token");
                return;
            }
            //從資料庫校驗
            UserDetails userDetails = customUserDetailsService.loadUserByUserId((Long) userId);
            //
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
         //放入使用者資訊
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        chain.doFilter(request, response);
    }


    @SneakyThrows
    public void writer(HttpServletResponse response,String msg){
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_OK);
        response.getWriter().write(objectMapper.writeValueAsString(R.error(HttpServletResponse.SC_UNAUTHORIZED,msg)));
    }
}

3handler 設定

/**
 * @Description //TODO $
 * @Date 21:06
 * @Author [email protected]
 **/
//登陸成功handler  登陸成功後獲取資訊存到redis和返回資料 這裡應該是存放更新redis資料
@Slf4j
@Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private RedisTemplate redisTemplate;

    private ObjectMapper objectMapper = new ObjectMapper();

    @SneakyThrows
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication){
        String token;
        Long userId = 0l;
        if(authentication.getPrincipal() instanceof CustomUserDetailsUser){
            //
            CustomUserDetailsUser userDetailsUser = (CustomUserDetailsUser) authentication.getPrincipal();
            token = SecureUtil.md5(userDetailsUser.getUsername() + System.currentTimeMillis());
            userId = userDetailsUser.getUserId();
        }else {
            token = SecureUtil.md5(String.valueOf(System.currentTimeMillis()));
        }
        //redis放token
        redisTemplate.opsForValue().set(Constant.AUTHENTICATION_TOKEN + token,token,Constant.TOKEN_EXPIRE, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(token,userId,Constant.TOKEN_EXPIRE, TimeUnit.SECONDS);

        response.setCharacterEncoding(CharsetUtil.UTF_8);
        //網頁頭
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        //登陸成功了加token到瀏覽器 ?
        PrintWriter printWriter = response.getWriter();
        printWriter.append(objectMapper.writeValueAsString(R.ok().put(Constant.TOKEN,token)));
    }
}

失敗

/**
 * @Description //TODO $
 * @Date 21:05
 * @Author [email protected]
 **/
//失敗 handler
@Slf4j
@Component
public class CustomAuthenticationFailHandler implements AuthenticationFailureHandler {

    private ObjectMapper objectMapper = new ObjectMapper();

    @SneakyThrows
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception){
        response.setCharacterEncoding(CharsetUtil.UTF_8);
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        PrintWriter printWriter = response.getWriter();
        printWriter.append(objectMapper.writeValueAsString(R.error(exception.getMessage())));
    }
}