spring security 使用总结
两大核心:1、认证 2授权
认证:就是常见的用户名密码校验 通过实现UserDetailsService 中 loadUserByUsername 方法 完成用户认证
授权:通过继承BasicAuthenticationFilter实现doFilterInternal 方法实现授权 (暂时还未用到,个人理解,期待指导)
spring security 里面封装的内容很多 里面都是通过filter使用责任链的模式来实现的
暂时只用到了认证
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {
private UserDetailsService userDetailsService;
private TokenManager tokenManager;
private IndustryPasswordEncoder industryPasswordEncoder;
private RedisTemplate redisTemplate;
@Reference
private UserInfoService userInfoService;
@Autowired
public TokenWebSecurityConfig(UserDetailsService userDetailsService, IndustryPasswordEncoder industryPasswordEncoder,
TokenManager tokenManager, RedisTemplate redisTemplate) {
this.userDetailsService = userDetailsService;
this.industryPasswordEncoder = industryPasswordEncoder;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().invalidSessionStrategy(new MyInvalidSessionStrategy())
.and().exceptionHandling()
.authenticationEntryPoint(new CustomAuthenticationEntryPoint()) //屏蔽密码错误弹框
.and().csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().logout().logoutUrl("/logout")
.addLogoutHandler(new TokenLogoutHandler(tokenManager, redisTemplate))
.and()
.rememberMe().key("xxx").alwaysRemember(true)
.rememberMeServices(new RememberMeServiceImpl(userInfoService, authenticationManager()))
//.addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate)) //登录认证过滤器
//.addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate))//授权filter暂时不需要
.and()
.httpBasic();
}
//屏蔽密码错误弹框
class CustomAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
CustomAuthenticationEntryPoint() {
this.setRealmName("xxx");
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException {
// 能屏蔽掉浏览器弹出登录框
response.setHeader("WWW-Authenticate", "FormBased");
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
// 自定义401处理
response.getWriter().write(JSONObject.toJSONString(ApiResponse.error(401, "用户名或者密码错误")));
}
}
//配置不要拦截的请求
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/test1", "/test/test2");
}
}
记住我过滤器:用于业务场景小程序登陆 前端会将openid放入header中 重写autoLogin方法
public class RememberMeServiceImpl implements RememberMeServices {
private UserInfoService userInfoService;
private AuthenticationManager authenticationManager;
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
public RememberMeServiceImpl(UserInfoService userInfoService, AuthenticationManager authenticationManager) {
this.userInfoService = userInfoService;
this.authenticationManager = authenticationManager;
}
@Override
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
String openid = request.getHeader("user-source");
log.info("autoLogin:{}", openid);
//只有小程序 走rememberme
if (StringUtils.isBlank(openid)) {
return null;
}
UserBean userBean = userInfoService.getUserMsgByOpenid(openid);
if (userBean == null) {
return null;
}
SimpleGrantedAuthority grantedAuthority = new SimpleGrantedAuthority("USER");
IndustrySessionInfo info = new IndustrySessionInfo(userBean.getId().longValue()
, userBean.getUsername(), userBean.getPassword(), Collections.singletonList(grantedAuthority));
RememberMeAuthenticationToken auth = new RememberMeAuthenticationToken("qianlima", info, new ArrayList<>());
auth.setDetails(this.authenticationDetailsSource.buildDetails(request));
return auth;
}
@Override
public void loginFail(HttpServletRequest httpServletRequest, HttpServletResponse response) {
}
@Override
public void loginSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
}
}
到这暂时就结束了,只是security认证的简单使用,后续会继续扩展更新,技术道路永无止路,继续成长