Spring Security简介及SpringBoot整合Security

()Spring Security简介

简介

Spring Security是一个专注于为Java应用程序提供身份认证和授权的框架,它的强大之处在于它可以轻松扩展以满足自定义的需求。

特点

  • 对身份的认证和授权提供全面的、可扩展的支持。
  • 防止各种攻击,如会话固定攻击、点击劫持、csrf攻击等。
  • 支持Servlet API、SpringMVC等Web技术集成。

SpringBoot整合Security

1、引入依赖

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

2、用户类实现UserDetails接口,并实现方法

    /**
     *
     * @return true:账号未过期
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     *
     * @return true:账号未锁定
     */
    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    /**
     *
     * @return  true:凭证未过期
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     *
     * @return  true:账号可用
     */
    @Override
    public boolean isEnabled() {
        return true;
    }
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     *
     * @return  返回用户的权限集合(一个用户可以有多个权限)
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> list=new ArrayList<>();
        list.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                //type=1时代表用户为超级管理员,2代表普通用户
                switch (type){
                    case 1:
                        return "ADMIN";
                    default:
                        return "USER";
                }
            }
        });
        return list;
    }
3、UserService实现UserDetailsService接口并实现接口方法(能够自动判断用户登陆时账号密码是否正确)
   /**
     * 此方法底层可以自动判断账号与密码是否正确
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return null;
    }
4、编写一个SecurityConfig配置类,来配置相关信息
package com.nowcoder.community.config;

import com.nowcoder.community.entity.User;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.util.CommunityUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
import sun.security.krb5.Config;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserService userService;
    @Override
    public void configure(WebSecurity web) throws Exception {
        //忽略静态资源的访问
        web.ignoring().antMatchers("/resources/**");
    }
    /**
     * AuthenticationManager:认证的接口
     * AuthenticationManagerBuilder:创建AuthenticationManager的工具
     * ProvideManager:AuthenticationManager接口的实现类
     * **/
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //内置的认证规则
        //Pbkdf2PasswordEncoder加密方式,盐:1234
        auth.userDetailsService(userService).passwordEncoder(new Pbkdf2PasswordEncoder("12345"));
        //自定义认证规则
        //AuthenticationProvider:ProvideManager持有一组AuthenticationProvider,每个AuthenticationProvider负责一组认证,为了兼容所有的认证
        //委托模式:ProvideManager将认证委托给AuthenticationProvider
        auth.authenticationProvider(new AuthenticationProvider() {
            //Authentication:用于封装认证信息的接口,不同的实现类代表不同类型的认证信息
            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                String username= authentication.getName();
                String password= (String) authentication.getCredentials();
                User user = userService.findUserByName(authentication.getName());
                if(user==null){
                    throw  new UsernameNotFoundException("账号不存在!");
                }
                password = CommunityUtil.md5(password + user.getSalt());
                if(password!=user.getPassword()){
                    throw new BadCredentialsException("密码不正确!");
                }
                //参数:principal:主要信息,credentials证书,authorities权限
                return new UsernamePasswordAuthenticationToken(user,password,user.getAuthorities());
            }
            //返回支持的哪中认证类型(以下支持账号密码认证)
            @Override
            public boolean supports(Class<?> authentication) {
                //UsernamePasswordAuthenticationToken:Authentication接口常用实现类
                return UsernamePasswordAuthenticationToken.class.equals(authentication);
            }
        });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登录相关配置
        http.formLogin()
                .loginPage("/loginpage")//登录页面
                 .loginProcessingUrl("/login")//拦截的请求路径
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.sendRedirect(httpServletRequest.getContextPath()+"/index");//重定向到首页,属于不同的请求
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
                           request.setAttribute("error",e.getMessage());//设置错误信息参数
                        request.getRequestDispatcher("/loginpage").forward(request,response);//请求转发属于同一次请求,可以携带参数
                    }
                });
        //退出相关配置
        http.logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.sendRedirect(request.getContextPath()+"/index");

                    }
                });
        //权限配置
        http.authorizeRequests()
                  .antMatchers("/letter").hasAnyAuthority("USER","ADMIN")//只有用户和管理员可以访问这个路径
                  .antMatchers("/admin").hasAnyAuthority("ADMIN")
                  .and().exceptionHandling().accessDeniedPage("/denied");//拒绝访问时给用户返回一个提示页面
        //增加Filter,处理验证码
        http.addFilterBefore(new Filter() {
            @Override
            public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
             //将ServletRequest和ServletResponse对象转成子类(HttpServletRequest,HttpServletResponse)子类的方法丰富
                HttpServletRequest request=(HttpServletRequest)servletRequest;
                HttpServletResponse response=(HttpServletResponse) servletResponse;
                if(request.getServletPath().equals("/login")){
                    String verifyCode=request.getParameter("verifyCode");
                    //因为是测试,所以将验证码写死为1234
                    if(verifyCode==null||!verifyCode.equalsIgnoreCase("1234")){
                        request.setAttribute("error","验证码错误");
                        request.getRequestDispatcher("/loginpage").forward(request,response);
                        return;
                    }
                }
                //让请求继续向下执行
                filterChain.doFilter(request,response);
            }//在账号认证前检查验证码是否正确
        },UsernamePasswordAuthenticationFilter.class);
          //记住我
        http.rememberMe()
                .tokenRepository(new InMemoryTokenRepositoryImpl())
                .tokenValiditySeconds(3600*24)
                .userDetailsService(userService);

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大磊程序员(“hello world”)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值