springsecurity 总结

spring security是安全框架,最常使用的是认证和授权,认证是登录操作,授权是针对请求访问的限制。

在项目开发中正常情况下,认证和授权需要自定义一些功能

认证

登录逻辑(实现UserDetailsService接口)

从数据库中获取数据

@Component
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleMapper roleMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据username获取user信息
        com.marw.sys.entity.User user=userMapper.findUserByUsername(username);

        if(user==null){
            throw new UsernameNotFoundException("用户不存在");
        }

        user.setPassword(passwordEncoder.encode(user.getPassword()));
        //根据UserID获取菜单
        List<RoleExtendMap> menuList = roleMapper.findRoleByUsreId(user.getId());

        SecurityUser securityUser = new SecurityUser(user, menuList);
        return securityUser;
    }
}

授权

登录前操作(UsernamePasswordAuthenticationFilter过滤器中attemptAuthentication方法)

获取表单提交的用户名和密码

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (this.postOnly && !request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        } else {
            String username = this.obtainUsername(request);
            username = username != null ? username : "";
            username = username.trim();
            String password = this.obtainPassword(request);
            password = password != null ? password : "";
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }

登录成功操作,登录失败操作(在UsernamePasswordAuthenticationFilter父类

AbstractAuthenticationProcessingFilter过滤器中successfulAuthentication、unsuccessfulAuthentication方法)

    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        SecurityContextHolder.getContext().setAuthentication(authResult);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));
        }

        this.rememberMeServices.loginSuccess(request, response, authResult);
        if (this.eventPublisher != null) {
            this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
        }

        this.successHandler.onAuthenticationSuccess(request, response, authResult);
    }

    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) 
        throws IOException, ServletException { SecurityContextHolder.clearContext(); this.logger.trace("Failed to process authentication request", failed); this.logger.trace("Cleared SecurityContextHolder"); this.logger.trace("Handling authentication failure"); this.rememberMeServices.loginFail(request, response); this.failureHandler.onAuthenticationFailure(request, response, failed); }

自定义登录前、登录成功和登录失败操作就可以继承UsernamePasswordAuthenticationFilter并重写这三个方法

授权设置(BasicAuthenticationFilter过滤器中doFiler)

授权的本质:权限信息交给权限上下文

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            UsernamePasswordAuthenticationToken authRequest = this.authenticationConverter.convert(request);
            if (authRequest == null) {
                this.logger.trace("Did not process authentication request since failed to find username and password in Basic Authorization header");
                chain.doFilter(request, response);
                return;
            }

            String username = authRequest.getName();
            this.logger.trace(LogMessage.format("Found username '%s' in Basic Authorization header", username));
            if (this.authenticationIsRequired(username)) {
                Authentication authResult = this.authenticationManager.authenticate(authRequest);
               //权限信息存储在权限上下文中  
          SecurityContextHolder.getContext().setAuthentication(authResult);
if (this.logger.isDebugEnabled()) { this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult)); } this.rememberMeServices.loginSuccess(request, response, authResult); this.onSuccessfulAuthentication(request, response, authResult); } } catch (AuthenticationException var7) { SecurityContextHolder.clearContext(); this.logger.debug("Failed to process authentication request", var7); this.rememberMeServices.loginFail(request, response); this.onUnsuccessfulAuthentication(request, response, var7); if (this.ignoreFailure) { chain.doFilter(request, response); } else { this.authenticationEntryPoint.commence(request, response, var7); } return; } chain.doFilter(request, response); }

未授权(实现AuthenticationEntryPoint接口)

public class Http403ForbiddenEntryPoint implements AuthenticationEntryPoint {
    private static final Log logger = LogFactory.getLog(Http403ForbiddenEntryPoint.class);

    public Http403ForbiddenEntryPoint() {
    }

    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException {
        logger.debug("Pre-authenticated entry point called. Rejecting access");
        response.sendError(403, "Access Denied");
    }
}

SpringSecurity配置类

作用:设置认证和授权

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsServiceImpl;//自定义认证操作

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //指定认证和加密方式
        auth.userDetailsService(userDetailsServiceImpl).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().authenticationEntryPoint(new 自定义未授权类)
                .addFilter(new 自定义过滤器);//可以实现认证前后操作和授权数据的设置
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        //return new BCryptPasswordEncoder();
        //自定义MD5加密
        return new MD5PasswordEncoder();
    }
}

 

posted @ 2021-08-20 11:12  一杯水M  阅读(98)  评论(0编辑  收藏  举报