spring-security 记录笔记02

配置中之前我们写了关于密码模块是这样的:

@Bean
PasswordEncoder PasswordEncoder(){
    return  NoOpPasswordEncoder.getInstance();
}

这里配置不使用密码Encode策略,但是存储的密码要是明文显示的就非常危险,数据库泄露就什么都没了,我们这里需要配置下策略
1:MD5加密,这种加密方式随便搜索一下到处有(缺点:黑客搞出了一个交彩虹表的东西,所以现在MD5已经变成了伪不可加密)
2:Bcrypt加密,这种加密方式每次计算出来的值都不一样,所以安全性高(缺点个人认为可以忽略)
使用:
测试1:

String pwd=new BCryptPasswordEncoder().encode("admin123");
System.out.println(pwd);

反复运行这段代码,发现得到的值都是不一样的,非常棒
我们得到的值为:

$2a$10$Mlh4urQFaC5peoPRZOa6ruLM1qHrt5/93Wz2IYNtAExj7OanYiuty
$2a$10$j9E4pPQUJ6eL1h.56/MOw.nvtsefar/FxjZU2l.sjClbEYjUDM/Ye
$2a$10$jLwDEkHrFiWYDeRFy3DcHOoYJ3jJtlAtANF7f.A2abYZBLFr6AQtu

调用提供的方法
在这里插入图片描述

得到的结果是我们所预期的结果

我们现在把这种密码策略应用到我们的spring security中去

@Bean
PasswordEncoder PasswordEncoder(){
    return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    DaoAuthenticationProvider authenticationProvider =new DaoAuthenticationProvider();
    authenticationProvider.setPasswordEncoder(PasswordEncoder());
    auth.inMemoryAuthentication().withUser("admin").password("$2a$10$jLwDEkHrFiWYDeRFy3DcHOoYJ3jJtlAtANF7f.A2abYZBLFr6AQtu").roles("admin")
            .and()
            .withUser("zhangsan").password("123").roles("user");
}

这里因为我们是使用自己设置的账户密码,所以把转码过后的密码填写进去
还有注意的是

@EnableGlobalMethodSecurity(prePostEnabled=true

这个必须启用这个配置,实验完成

但是我们平时的用户数据记录是放在数据库中的,而不是再我们的配置文件中直接把用户名和密码配置的,就像我们之前配置的这样

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    DaoAuthenticationProvider authenticationProvider =new DaoAuthenticationProvider();
    authenticationProvider.setPasswordEncoder(PasswordEncoder());
    auth.inMemoryAuthentication().withUser("admin").password("$2a$10$jLwDEkHrFiWYDeRFy3DcHOoYJ3jJtlAtANF7f.A2abYZBLFr6AQtu").roles("admin")
            .and()
            .withUser("zhangsan").password("123").roles("user");
}

这种模式仅仅做测试用,我们生产环境下还是要依据数据中中的数据来保存用户信息
所以需要改版:
1:在项目中使用mybatis来完成从数据库读取数据
2:配置security完成从数据库加载数据的校验(代码连接在文章末尾)
这里我们需要关心的第一个类是UserDetails 这个类,源代码:

public interface UserDetails extends Serializable {
    Collection<? extends GrantedAuthority> getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

这个类包含某个用户的账号,密码,权限,状态(是否锁定)等信息。
实验目的:暂时使用spring security自带的登录页面完成spring security登录操作
注意点:因为现在项目都是前后端分离项目,所以我们将登录成功与否的功能交由json返回给前端

完成UserDetailService的编写

public class UserDetailService implements UserDetailsService {
    @Autowired
    private UserService userService;
    @Override
    public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
        User u=userService.findUserByName(name);
        if (u==null){
            throw new UsernameNotFoundException(null);
        }
        org.springframework.security.core.userdetails.User user = new org.springframework.security.core.userdetails.User(u.getUsername(), u.getPassword(), true, true, true, true,getGrantedAuthority(u));
        return user;
    }
    public List<GrantedAuthority> getGrantedAuthority(User user){
        List<GrantedAuthority> list = new ArrayList<>();
        list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        return list;
    }
}

这里loadUserByUsername就是用于加载用户,如果u==null 代表查询部出来任何对象,就返回UsernameNotFoundException ,如果能查询出来对象,就组建userdetails.User对象,由该对象判断是否登录成功

编写类:CustomAuthenticationSuccessHandler
该类用户登录成功的处理函数

public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> data = new HashMap<>();
        String responseJSONObject ="";
        data.put("code", ResultCode.SUCCESS.val());
        data.put("message",ResultCode.SUCCESS);
        responseJSONObject = JSONObject.toJSONString(data);
        PrintWriter out = response.getWriter();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        out.print(responseJSONObject);
    }
}

这里返回的就是json

编写类CustomAuthenticationFailureHandler

public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
   @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
       Map<String, Object> data = new HashMap<>();
        String responseJSONObject ="";
        if(e instanceof UsernameNotFoundException || e instanceof BadCredentialsException){
            data.put("code",ResultCode.LOGIN_FAIL.val());
            data.put("message",ResultCode.LOGIN_FAIL);
            responseJSONObject = JSONObject.toJSONString(data);
        }

        PrintWriter out = response.getWriter();
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        out.print(responseJSONObject);
    }
}

这里通过返回的异常判断是为什么失败的
UsernameNotFoundException -代表没有找到这个对象
BadCredentialsException-错误的账户名/密码

最后完成配置,去掉之前我们手动添加的账户名和密码

@Bean
AuthenticationFailureHandler customAuthenticationFailureHandler(){
    return new CustomAuthenticationFailureHandler();
}
@Bean
CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler(){
    return new CustomAuthenticationSuccessHandler();
}
@Bean
UserDetailsService customUserService(){
    return new UserDetailService();
}
@Bean
PasswordEncoder PasswordEncoder(){
    return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   auth.userDetailsService(customUserService()).passwordEncoder(PasswordEncoder());
}

这里AuthenticationManagerBuilder 就不是自己写的而是通过customUserService()获取
最后配置

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/sayHello").hasRole("admin")
            .anyRequest().authenticated()
            .and().formLogin().permitAll()
            .successHandler(customAuthenticationSuccessHandler())
            .failureHandler(customAuthenticationFailureHandler())
            .and().csrf().disable();
}

这样,successHandler和failureHandler就换成我们自己写的上述类

最后运行代码,当登录成功/失败的时间返回json格式字符串

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值