springboot security 安全机制


springboot security 安全机制

 

认证流程:

1、由认证配置WebSecurityConfigurerAdapter的configure(HttpSecurity http)方法进入,添加拦截器addFilterBefore
2、进入拦截器AbstractAuthenticationProcessingFilter的attemptAuthentication方法,指定认证对象AbstractAuthenticationToken
3、进入认证逻辑AuthenticationProvider,根据supports的断定对认证的目标对象指定对哪个拦截器进行认证,进入具体的认证逻辑方法authenticate
4、认证结果:认证成功后进入拦截器的successfulAuthentication方法;认证失败后进入拦截器的unsuccessfulAuthentication方法
5、对认证结果进行处理
  a.认证成功的逻辑:进入SimpleUrlAuthenticationSuccessHandler的onAuthenticationSuccess方法
  b.认证失败的逻辑:进入SimpleUrlAuthenticationFailureHandler的onAuthenticationFailure方法
6、返回结果给页面,将数据封装在ObjectMapper对象中,将会以文本形式返回给客户端(页面)

 

 代码块

自定义认证配置,实现WebSecurityConfigurerAdapter 

package com.travelsky.config; import com.travelsky.auto.login.BeforeLoginFilter; import com.travelsky.auto.login.LoginProvider; import com.travelsky.auto.login.OnFailureLogin; import com.travelsky.auto.token.OnFailureToken; import com.travelsky.auto.token.TokenFilter; import com.travelsky.auto.token.TokenProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** * 认证配置 */ @Configuration public class WebSecurityConfigurer  extends WebSecurityConfigurerAdapter { /** * 认证成功处理 */ @Autowired private SimpleUrlAuthenticationSuccessHandler successHandler; /** * 登录认证失败后处理 */ @Autowired private OnFailureLogin failureHandler; /** * token认证失败后处理 */ @Autowired private OnFailureToken onFailureToken; /** * 登录认证逻辑 */ @Autowired private LoginProvider loginProvider; /** * token认证逻辑 */ @Autowired private TokenProvider tokenProvider; /** * 配置请求权限 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // 允许登录路径通过
                     .antMatchers("/login").permitAll() // 允许业务路径通过
                     .antMatchers("/**").permitAll() .and() .authorizeRequests() .anyRequest() .authenticated() .and() .csrf().disable() // 添加拦截器
                     .addFilterBefore(getLoginFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(getTokenFilter(), UsernamePasswordAuthenticationFilter.class); } /** * 登录拦截器 * @return * @throws Exception */
    private AbstractAuthenticationProcessingFilter getLoginFilter() throws Exception { BeforeLoginFilter beforeLoginFilter = new BeforeLoginFilter("/login", successHandler, failureHandler); beforeLoginFilter.setAuthenticationManager(super.authenticationManager()); return beforeLoginFilter; } /** * token拦截器 * @return * @throws Exception */
    private AbstractAuthenticationProcessingFilter getTokenFilter() throws Exception { TokenFilter tokenFilter = new TokenFilter("/**", onFailureToken); tokenFilter.setAuthenticationManager(super.authenticationManager()); return tokenFilter; } /** * 配置认证逻辑列表,按顺序进行认证 * @param auth */ @Override protected void configure(AuthenticationManagerBuilder auth) { auth.authenticationProvider(loginProvider); auth.authenticationProvider(tokenProvider); } }

 

 

自定义拦截器,继承AbstractAuthenticationProcessingFilter

package com.travelsky.auto.login; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 登录自定义拦截器,继承AbstractAuthenticationProcessingFilter */ @Slf4j public class BeforeLoginFilter extends AbstractAuthenticationProcessingFilter { /** *认证成功的处理对象 */
    private AuthenticationSuccessHandler successHandler; /** * 认证失败的处理对象 */
    private AuthenticationFailureHandler failureHandler; public BeforeLoginFilter(String defaultFilterProcessesUrl, AuthenticationSuccessHandler successHandler, AuthenticationFailureHandler failureHandler) { super(defaultFilterProcessesUrl); this.successHandler = successHandler; this.failureHandler = failureHandler; } /** * 过滤器处理逻辑 * @param request * @param response * @return * @throws AuthenticationException * @throws IOException * @throws ServletException */ @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { log.info("进入登录过滤器"); String userName = request.getParameter("userName"); String password = request.getParameter("password"); LoginInfo loginInfo = new LoginInfo(null, userName, password); log.info("username = {}", userName); log.info("password = {}", password); // 返回指定的认证对象
           LoginAuthenticationToken loginAuthentication = new LoginAuthenticationToken(null, loginInfo, null); // 将来由认证逻辑AuthenticationProvider来处理,这里返回LoginAuthenticationToken对象,将来由AuthenticationProvider的supports方法相匹配的认证逻辑来处理
           return this.getAuthenticationManager().authenticate(loginAuthentication); } /** * 认证逻辑认证成功成功后会调用此方法 * @param request * @param response * @param chain * @param authResult * @throws IOException * @throws ServletException */ @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { successHandler.onAuthenticationSuccess(request, response, authResult); } /** * 认证逻辑认证失败后调用此方法 * @param request * @param response * @param failed * @throws IOException * @throws ServletException */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { failureHandler.onAuthenticationFailure(request, response, failed); } }

 

自定义认证逻辑,继承AuthenticationProvider

package com.travelsky.auto.login; import com.alibaba.fastjson.JSONObject; import com.travelsky.pojo.MenuVO; import com.travelsky.pojo.SysUserInfo; import com.travelsky.service.SysUserInfoService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.stereotype.Component; import java.util.List; /** * 认证逻辑 */ @Component @Slf4j public class LoginProvider implements AuthenticationProvider { @Autowired private SysUserInfoService userInfoService; /** * 认证逻辑,认证的目标对象由supports断定,supports断定的目标对象是LoginAuthenticationToken自定义认证对象 * @param authentication * @return * @throws AuthenticationException */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { log.info("登录验证器,接收参数:{}", JSONObject.toJSONString(authentication)); // Authentication的具体子类,可由supports断定,supports断定子类是LoginAuthenticationToken,因此可以强转
           final LoginAuthenticationToken loginAuthentication = (LoginAuthenticationToken) authentication; final LoginInfo loginInfo = loginAuthentication.getLoginInfo(); final String userName = loginInfo.getUserName(); final SysUserInfo userInfo = userInfoService.getByUserId(userName); if (userInfo.getPassword().equals(loginInfo.getPassword())) { final List<MenuVO> userInfoMenus = userInfoService.getUserInfoMenus(userInfo.getId()); return new LoginAuthenticationToken(null, loginInfo, userInfoMenus); } else { log.error("登录验证失败"); throw new AuthenticationServiceException("登录失败........."); } } /** * 指定对谁进行认证,这里指定对LoginAuthenticationToken自定义认证对象进行认证 * @param authentication * @return
     */ @Override public boolean supports(Class<?> authentication) { return LoginAuthenticationToken.class.isAssignableFrom(authentication); } }

 

自定义认证成功的处理逻辑,继承SimpleUrlAuthenticationSuccessHandler

package com.travelsky.auto.login; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import com.travelsky.auto.token.TokenContent; import com.travelsky.auto.token.TokenFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 自定义认证成功处理逻辑,继承SimpleUrlAuthenticationSuccessHandler类 */ @Component @Slf4j public class OnSuccessfulLogin extends SimpleUrlAuthenticationSuccessHandler { /** * 返回页面的对象,可将对象转化为文本形式(json格式) */ @Autowired private ObjectMapper objectMapper; /** * token工厂 */ @Autowired private TokenFactory tokenFactory; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { log.info("登录认证成功,传入参数:{}", JSONObject.toJSONString(authentication)); // 配置响应编码格式为UTF-8
           response.setCharacterEncoding("UTF-8"); // 配置返回格式为json
 response.setContentType(MediaType.APPLICATION_JSON_VALUE); // Authentication的具体子类为LoginAuthenticationToken
           final LoginAuthenticationToken loginAuthenticationToken = (LoginAuthenticationToken) authentication; final TokenContent tokenContent = tokenFactory.createToken("token"); JSONObject json = new JSONObject(); json.put("code", "000000"); json.put("message", "认证成功"); json.put("claims", tokenContent.getClaims()); json.put("token", tokenContent.getToken()); json.put("menuList", loginAuthenticationToken.getUserInfoMenus()); log.info("生产token:{}",tokenContent.getToken()); // 将数据保存到objectMapper中,将会转化为文本格式,返回给页面
 objectMapper.writeValue(response.getWriter(), json); } }

 

自定义认证失败逻辑,继承SimpleUrlAuthenticationFailureHandler

package com.travelsky.auto.login; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Slf4j @Component public class OnFailureLogin extends SimpleUrlAuthenticationFailureHandler { @Autowired private ObjectMapper objectMapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { log.info("登录认证失败,传入参数:{}", JSONObject.toJSONString(exception)); response.setCharacterEncoding("UTF-8"); response.setContentType(MediaType.APPLICATION_JSON_VALUE); JSONObject json = new JSONObject(); json.put("code", "999999"); json.put("message", exception.getMessage()); objectMapper.writeValue(response.getWriter(), json); } }

 

 

 

自定义认证对象,继承AbstractAuthenticationToken

package com.travelsky.auto.login; import com.travelsky.pojo.MenuVO; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import java.util.Collection; import java.util.List; /** * 自定义登录认证对象 */
public class LoginAuthenticationToken extends AbstractAuthenticationToken { /** * 登录数据对象 */
    private LoginInfo loginInfo; /** * 菜单数据对象 */
    private List<MenuVO> userInfoMenus; LoginAuthenticationToken(Collection<? extends GrantedAuthority> authorities, LoginInfo loginInfo, List<MenuVO> userInfoMenus) { super(authorities); this.userInfoMenus = userInfoMenus; this.loginInfo = loginInfo; } @Override public Object getCredentials() { return loginInfo.getPassword(); } @Override public Object getPrincipal() { return loginInfo.getUserName(); } public LoginInfo getLoginInfo() { return loginInfo; } public List<MenuVO> getUserInfoMenus() { return userInfoMenus; } }

 

自定义拦截器:继承AbstractAuthenticationProcessingFilter,重写attemptAuthentication(HttpServletRequest request, HttpServletResponse response) 方法,返回AbstractAuthenticationToken的子类,AbstractAuthenticationToken的子类可自己定义内容(例如:用户信息,token字符串,Claims),只要继承AbstractAuthenticationToken即可

自定义验证规则:实现AuthenticationProvider接口,authenticate方法参数Authentication与拦截器attemptAuthentication方法返回的是同一个对象,重写 authenticate(Authentication authentication),其中supports(Class<?> authentication)方法用来指定当前检验规则是针对哪个AbstractAuthenticationToken子类对象。springboot自带默认的登录验证是返回UsernamePasswordAuthenticationToken对象。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM