前幾天改造舊系統springsecurity 傳統mvc 改成 springboot 和前后端 分離。springsecurity 的概念我就不講了,具體可以百度 看看 流程 ,其實就是一系列的過濾器鏈,職責分離,委托處理。
步驟 梭哈了 ,再也不用擔心 自己不會springsecurity 前后端分離了
- 定義filter 加入 過濾鏈前面 ,禁用session,定義各種處理器
- 認證(自定義 UserDetails,UserDetailsService 的實現)成功后,生成token
- 自定義filter ,查看token redis 里面查找 認證信息,重新 寫到上下文 認證信息 大功告成了基本
- 認證 信息 基本就是用戶的菜單,權限,用戶名 等 基本信息。
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());
}
核心代碼 如下

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