Security总结记录

Security总结

  1. 加入依赖
  2. 配置WebSecurityConfig(3个重写)

加入依赖

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

配置WebSecurityConfig

WebSecurityConfig继承WebSecurityConfigurerAdapter,需要重写以下三个方法
 @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //定义用户(user )、 密码(password )和角色 ( role )
}

 @Override
    protected void configure(HttpSecurity http) throws Exception {
    //指定用户和角色与对应 URL 的访问权限
}

 @Override
    public void configure(WebSecurity web) throws Exception {
    //配置 Filter 链的内容,可以配置 Filter 链忽略哪些内容
}

AuthenticationManagerBuilder 

通常自定义CustomAuthenticationProvider处理用户名,密码和角色;

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

CustomAuthenticationProvider继承AbstractUserDetailsAuthenticationProvider类,主要重写以下方法:

public class CustomAuthenticationProvider  extends AbstractUserDetailsAuthenticationProvider {

    @Autowired
    private CustomUserDetailsService customUserDetailsService;
    /**
     * 校验密码有效性.
     *
     * @param userDetails  用户正确的密码  .
     * @param authentication .传过来的账户密码
     * @throws AuthenticationException .
     */
    @Override
    protected void additionalAuthenticationChecks(
            UserDetails userDetails, UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        String value = (String)authentication.getCredentials();
        System.out.println("additionalAuthenticationChecks"+value);
        /*
            判断userDetails 和 authentication是否一致
        */
    }

    /**
     * 获取用户.
     *     .
     * @param authentication .
     * @return
     * @throws AuthenticationException .
     */
    @Override
    protected UserDetails retrieveUser(
            String wxCode, UsernamePasswordAuthenticationToken authentication)
            throws AuthenticationException {
        System.out.println("retrieveUser "+ wxCode);
        UserDetails loadedUser = customUserDetailsService.loadUserByUsername(wxCode);
        if (loadedUser == null) {
            throw new InternalAuthenticationServiceException(
                    "UserDetailsService returned null, which is an interface contract violation");
        }
        return loadedUser;
    }
    /**
     * 授权持久化.
     */
    @Override
    protected Authentication createSuccessAuthentication(Object principal,
                                                         Authentication authentication, UserDetails user) {
        return super.createSuccessAuthentication(principal, authentication, user);
    }

additionalAuthenticationChecks用来校验数据库存储用户UserDetail和传来的用户是否一致;retrieveUser则是需要根据用户名去查找数据库对应用户 返回一个UserDetails;

@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private WxUserService wxUserService;

    @Autowired
    private RoleService roleService;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        String sessionId = username;// 我们保存的是sessionId
        // 从数据库中取出用户信息
        WxUser user = wxUserService.getWxUser(sessionId);
        if(user == null){
            log.error("{} 不存在SessionId", sessionId);
            throw new AuthenticationServiceException(JsonUtils.obj2String(new ErrorInfo(101, sessionId)));
        }
        // 添加权限
        Role role = roleService.selectById(user.getRole());
        authorities.add(new SimpleGrantedAuthority(role.getName()));

        // 返回UserDetails实现类
        return new org.springframework.security.core.userdetails.User(user.getOpenId(), user.getUsername(), authorities);
    }
}

HttpSecurity http

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/static/**","/wx/none/**","/security/sign", "/test/**").permitAll()
                .anyRequest().authenticated() // 其余的所有请求都需要验证
                .and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/security/logout")).logoutSuccessHandler(customLogoutSuccessHandler)
                .and().csrf().disable() // 禁用CSRF
                ;


        //用重写的Filter替换掉原有的UsernamePasswordAuthenticationFilter
        http.addFilterAt(customAuthenticationFilter(),
                UsernamePasswordAuthenticationFilter.class);

    }
@Bean
    JsonUsernamePasswordAuthenticationFilter customAuthenticationFilter() throws Exception {
        JsonUsernamePasswordAuthenticationFilter filter = new JsonUsernamePasswordAuthenticationFilter();
        filter.setFilterProcessesUrl("/security/login");
        filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
        filter.setAuthenticationFailureHandler(customAuthenticationFailHandler);
        //这句很关键,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己组装AuthenticationManager
        filter.setAuthenticationManager(authenticationManagerBean());
        return filter;
    }

其中:http对应的方法有如下方法

我们自定义如下验证规则:

public class JsonUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        UsernamePasswordAuthenticationToken authRequest;
        //attempt Authentication when Content-Type is json
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(messages.getMessage("8000", "非POST请求"));
        } else {
            String sessionId = request.getParameter("openId");
            if(sessionId != null && sessionId.equals("")){
                throw new AuthenticationServiceException(messages.getMessage("8001", "openId为空"));
            }
            // 就是我们要的Authentication
            authRequest = new UsernamePasswordAuthenticationToken(sessionId, "");
            this.setDetails(request, authRequest);
            return this.getAuthenticationManager().authenticate(authRequest);
        }
    }
}

自定义登陆成功 登陆失败 退出 无权限访问页面

public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication)
            throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        String sessionId = request.getSession().getId();
        log.info("-------SessionId------- {} ", sessionId);
        // 登录成功后,返回json数据
        response.getWriter().append(JsonUtils.obj2String(JsonData.buildSuccess(200, sessionId)));
    }
}
@Component
public class CustomAuthenticationFailHandler implements AuthenticationFailureHandler {


    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=UTF-8");
        // 登录成功后,返回json数据
        httpServletResponse.getWriter().append(JsonUtils.obj2String(JsonData.buildError(500, "登陆失败", e.getMessage())));
    }
}
@Component
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                Authentication authentication) throws IOException, ServletException {
        if (authentication != null && authentication.getDetails() != null) {
            try {
                httpServletRequest.getSession().invalidate();
                //you can add more codes here when the user successfully logs out,
                //such as updating the database for last active.
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        httpServletResponse.setStatus(HttpServletResponse.SC_OK);
    }
}
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().append(JsonUtils.obj2String(JsonData.buildError(403, "无权限")));
    }
}

WebSecurity web

@Override
    public void configure(WebSecurity web) throws Exception {
        // 设置拦截忽略文件夹,可以对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**");
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Spring Security是一个功能强大且广泛使用的安全框架,它在保护应用程序的份认证和授权方面提供一系列功能和选项。它提供了许多内置的安全特性,例如用户认证、访问控制、会话管理、密码密等等。Spring在Web应用程序中广泛应用,可以轻松地集成到Spring框架中。 那么,是否有必要使用Spring Security取决于你的应用程序的需求和安全性要求。以下是一些使用Spring Security的场景: 1. 用户认证和授权:如果你的应用程序需要对用户进行认证和授权,确保只有授权用户可以访问特定的资源或执行特定的操作,那么Spring Security是一个非常好的选择。它提供了灵活的配置选项,可以根据你的需求进行自定义。 2. 密码加密:Spring Security提供了多种密码加密和哈希算法,可以帮助你存储用户密码的安全性。它可以防止明文密码泄露,并提供了一些防止密码攻击的选项。 3. 会话管理:Spring Security提供了会话管理功能,可以帮助你管理用户会话并保护用户的隐私。它支持各种会话存储选项,并提供了一些防止会话劫持和跨站点请求伪造(CSRF)的保护机制。 4. 安全事件和日志记录:Spring Security提供了安全事件和日志记录功能,可以帮助你监视和审计应用程序的安全状态。它可以记录登录尝试、访问被拒绝的资源等安全相关事件,帮助你及时发现和应对潜在的安全威胁。 总结来说,如果你的应用程序需要进行身份认证和授权,并且需要保护用户隐私和应对安全威胁,那么使用Spring Security是非常有必要的。它提供了许多功能和选项,可以帮助你构建安全可靠的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BugGuys

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值