基於 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());
    }
核心代碼 如下

是不是 超級簡單啊,答案 是的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM