基于 springboot+springsecurity 的前后端分离 实现

前几天改造旧系统springsecurity 传统mvc 改成 springboot 和前后端 分离。springsecurity 的概念我就不讲了,具体可以百度 看看 流程 ,其实就是一系列的过滤器链,职责分离,委托处理。

步骤 梭哈了 ,再也不用担心 自己不会springsecurity 前后端分离了

  1. 定义filter 加入 过滤链前面 ,禁用session,定义各种处理器
  2. 认证(自定义 UserDetails,UserDetailsService 的实现)成功后,生成token
  3. 自定义filter ,查看token redis 里面查找 认证信息,重新 写到上下文 认证信息 大功告成了基本
  4. 认证 信息 基本就是用户的菜单,权限,用户名 等 基本信息。
public class UserDetailsImpl implements UserDetails {
    private String userId;
    private String userName;
    private String password;
    private List<GrantedAuthority> authorities;
    private List<MenuVO> menuList;
}

public class UserDetailsServiceImpl implements UserDetailsService {
	@Autowired
	private UserDao userDao;
	
	private Logger logger = Logger.getLogger(UserDetailsServiceImpl.class);

	public org.springframework.security.core.userdetails.UserDetails loadUserByUsername(String userName)
			throws UsernameNotFoundException {
		User user = this.userDao.findByUserName(userName);
        }
}

/**
* token 过滤器
*/
@Component
public class TokenAuthenticationTokenFilter extends OncePerRequestFilter {


    @Autowired
    private AuthenticationFailureHandler authenctiationFailureHandler;

    @Autowired
    private RedisUtils redisUtils;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // 登陆请求 校验验证码
        if (StringUtils.equals("/account/doLogin", request.getRequestURI())
                && StringUtils.equalsIgnoreCase(request.getMethod(), "POST")) {
            try {
                //validate(request);
            } catch (ValidateCodeException e) {
                // 有异常就返回自定义失败处理器
                authenctiationFailureHandler.onAuthenticationFailure(request, response, e);
                return;
            }
        }

        String token = request.getHeader(UserConstant.TOKEN);
        if (token != null ) {
            String realToken = MessageFormat.format(RedisKey.SYSTEM_TOKEN, token);
            UserGrantedAuthority userGrantedAuthority = redisUtils.stringGet(realToken,UserGrantedAuthority.class);
            if (userGrantedAuthority != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                List<GrantedAuthority> grantedAuthorities = userGrantedAuthority.getAuthorities().stream().map(e -> new SimpleGrantedAuthority(e)).collect(Collectors.toList());
                String userId = userGrantedAuthority.getUserId();
                String username = userGrantedAuthority.getUsername();
                String password = userGrantedAuthority.getPassword();
                List<MenuVO> menus = userGrantedAuthority.getMenus();
                UserDetails userDetails = new UserDetailsImpl(userId,username,password,grantedAuthorities,menus);
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(userDetails, null, grantedAuthorities);
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                // 刷新token
                redisUtils.exportCache(realToken,UserConstant.TOKEN_EXPIRE, TimeUnit.MINUTES);
                // 刷新online list时间
                String userIdListKey = MessageFormat.format(RedisKey.SYSTEM_TOKEN_ONLINE, SecureUtil.md5(String.valueOf(userId)));
                redisUtils.exportCache(userIdListKey,UserConstant.TOKEN_EXPIRE, TimeUnit.MINUTES);

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }

        filterChain.doFilter(request, response);

    }

    /**
     * 校验验证码
     * @param request
     */
    private void validate(HttpServletRequest request) {
        String uuid = request.getParameter("uuid");
        String code = redisUtils.stringGet(MessageFormat.format(RedisKey.PICTURE_VERIFICATION_CODE, uuid));
        String verify = request.getParameter("verify");
        if (StringUtils.isBlank(code)) {
            throw new ValidateCodeException("验证码已过期!");
        }
        if (!StringUtils.equalsIgnoreCase(code, verify)) {
            throw new ValidateCodeException("验证码不匹配");
        }
        redisUtils.remove(code);

    }

}

// 核心配置
@Override
    protected void configure(HttpSecurity http) throws Exception {
        // 禁用 csrf, 由于使用的是JWT,我们这里不需要csrf
        http.cors().and().csrf().disable()
                // 基于token,所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                // 基于token,所以不需要session
                // 跨域预检请求
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

                // 登录URL
                .antMatchers("/account/doLogin").permitAll()
                .antMatchers("/imageGen/getSysManageLoginCode").permitAll()
                //.antMatchers("/**").permitAll()
                // swagger
                .antMatchers("/swagger**/**").permitAll()
                .antMatchers("/doc.html").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/v2/**").permitAll()
                .antMatchers("/profile/**").permitAll()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/*/api-docs").permitAll()
                .antMatchers("/druid/**").permitAll()
                // 其他所有请求需要身份认证
                .anyRequest().authenticated()
                .accessDecisionManager(roleAccessDecisionManager)
                .and()
                .headers().frameOptions().disable()
                .and()
                .formLogin()  //开启登录
                .loginProcessingUrl("/account/doLogin")
                .passwordParameter("loginPassWord").usernameParameter("userName")
                .successHandler(authenticationSuccessHandler) // 登录成功
                .failureHandler(authenticationFailureHandler) // 登录失败
                .permitAll();
        // 退出登录处理器
        //http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());
        // 开启登录认证流程过滤器
        http.addFilterBefore(tokenAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        http.logout().logoutUrl("/account/logout").logoutSuccessHandler(logoutSuccessHandler);
        http.exceptionHandling().accessDeniedHandler(new SimpleAccessDeniedHandler()).authenticationEntryPoint(new UnauthorizedEntryPoint());
    }
核心代码 如下

是不是 超级简单啊,答案 是的

posted @ 2020-09-01 15:31  川流不息&  阅读(4245)  评论(0编辑  收藏  举报