7.1 Spring Security入门和简单案例

Spring Security

• 简介

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

• 特征

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

官网:https://spring.io/projects/spring-security

中文学习网址:http://www.spring4all.com/article/428
在这里插入图片描述

1、引入Spring Security的依赖

  • 引入包的时候,Spring Security权限就会生效 ,会生成随机密码
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.6.4</version>
</dependency>

2、Security授权 需要字符串获取用户的权限

–实现指定Security的接口

–返回用户权限

// true: 账号未过期.

@Override
public boolean isAccountNonExpired() {
    return true;
}

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

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

// true: 账号可用.
@Override
public boolean isEnabled() {
    return true;
}

//返回用户具备的权限,可以具有很多权限
//通过GrantedAuthority()封装一个权限
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
    List<GrantedAuthority> list=new ArrayList<>();
    list.add(new GrantedAuthority() {
        @Override
        public String getAuthority() {
            switch (type){
                case 1:
                    return "ADMIN";
                default:
                    return "USER";
            }
        }
    });
    return list;
}



Security需要依赖UserDetailsService接口查询用户,所以需要在UserService实现此接口,并且实现其方法,直接返回UserService的查询方法;

@Service
public class UserService implements UserDetailsService {
  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
   return this.findUserByName(username);
  }
}

3、编写Security配置类

编写认证的逻辑

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserService userService;

    //忽略对静态资源请求的检查
    @Override
    public void configure(WebSecurity web) throws Exception  {
        web.ignoring().antMatchers("/resources/**");
    }

    //认证逻辑
    // AuthenticationManager: 认证的核心接口.
    // AuthenticationManagerBuilder: 用于构建AuthenticationManager对象的工具.
    // ProviderManager: AuthenticationManager接口的默认实现类.
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 内置的认证规则
        // auth.userDetailsService(userService).passwordEncoder(new Pbkdf2PasswordEncoder("12345"));

        // 自定义认证规则
        // AuthenticationProvider: ProviderManager持有一组AuthenticationProvider,每个AuthenticationProvider负责一种认证.
        // 委托模式: ProviderManager将认证委托给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(username);
                if(user==null){
                    throw new UsernameNotFoundException("账号不存在!");
                }

                //对密码进行加密
                password = CommunityUtil.md5(password + user.getSalt());
                if (!user.getPassword().equals(password)) {
                    throw new BadCredentialsException("密码不正确!");
                }

                // principal: 主要信息; credentials: 证书; authorities: 权限;
                return new UsernamePasswordAuthenticationToken(user,user.getPassword(),user.getAuthorities());
            }

            // 当前的AuthenticationProvider支持哪种类型的认证.

            @Override
            public boolean supports(Class<?> aClass) {
                // UsernamePasswordAuthenticationToken: Authentication接口的常用的实现类.
                //代表当前支持的账号密码认证
                return UsernamePasswordAuthenticationToken.class.equals(aClass);
            }

        });
    }

编写授权的逻辑

–父类中任何请求都要被权限认证

–重写此方法处理自己的业务

使用处理器和路径

传入接口自定义成功或者失败的处理逻辑

请求转发而不是重定向

在这里插入图片描述

//授权逻辑
@Override
protected void configure(HttpSecurity http) throws Exception {
    // 登录相关配置
    http.formLogin()
            .loginPage("/loginpage")     //登录页面
            .loginProcessingUrl("/login")    //处理请求的路径
            //传入成功的时候的处理逻辑
            .successHandler(new AuthenticationSuccessHandler() {
                @Override
                public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                    //请求重定向
                    response.sendRedirect(request.getContextPath() + "/index");
                }
            })
            .failureHandler(new AuthenticationFailureHandler() {
                @Override
                public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                    httpServletRequest.setAttribute("error",e.getMessage());
                    //请求转发
                    httpServletRequest.getRequestDispatcher("/loginpage").forward(httpServletRequest,httpServletResponse);
                }
            });

    // 退出相关配置
    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");
}

Security要求退出必须是POST请求

<li>
    <form method="post" th:action="@{/logout}">
        <a href="javascript:document.forms[0].submit();">退出</a>
    </form>
</li>

4、增加Filter,处理验证码

// 增加Filter,处理验证码
//在处理登录请求之前
http.addFilterBefore(new Filter() {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //转型
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //处理登录请求
        if (request.getServletPath().equals("/login")) {
            String verifyCode = request.getParameter("verifyCode");
            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);  //得到用户西信息
lterChain.doFilter(request, response);
    }
}, UsernamePasswordAuthenticationFilter.class);

// 记住我
http.rememberMe()
        .tokenRepository(new InMemoryTokenRepositoryImpl())
        .tokenValiditySeconds(3600 * 24)
        .userDetailsService(userService);  //得到用户西信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值