当前位置:   article > 正文

SpringSecurity基础入门(详情可以联系博主)_loaduserbyusername返回值作用

loaduserbyusername返回值作用

Spring Security

想要项目源码可以联系我,有问题看到就会回复,互相学习

登录认证

security登录功能,通过登录的用户名(username)来判断输入的用户名密码是否正确

security调用loadUserByUsername这个方法,通过用户名来加载用户信息,如果加载到了改用户名的用户信息,则登录成功

否则登录失败

而这个方法是UserDetailsService接口的唯一方法,所以我们只需要重写这个方法来帮助security完成对用户信息的加载

这个方法的返回值是UserDetails类型的对象,这个对象里面包含用户的用户名,密码,权限信息,

所以我们通过用户的实体类来实现UserDetails接口从而使security调用loadUserByUsername方法来获取UserDetails类型的返回值并完成登录校验工作,该接口还有isAccountNonExpired,isAccountNonLocked等方法,

这些方法的返回值都需要修改为true

security对核心接口UserDetailsUserDetailsService和核心方法loadUserByUsername的具体调用在源码中

已经封装好了,那我们如何配合security的源码来完成对这些核心接口和方法的调用呢,毫无疑问需要写一个security的配置类

WebSecurityConfig,该类继承WebSecurityConfigurerAdapter,并需要在该类上加上注解@EnableWebSecurity,

如果后面需要通过权限控制接口是否能被调用,我们还可以先加上注解@EnableGlobalMethodSecurity并传入以下参数

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true,jsr250Enabled = true)
  • 1

WebSecurityConfig继承WebSecurityConfigurerAdapter后需要重写1个核心方法

void configure(HttpSecurity http) throws Exception ;
  • 1

configure这个方法是用来可以用来配置登录,登出,是否需要权限控制等配置

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .antMatchers("/books","/main").authenticated()
                    .antMatchers("/**").permitAll()
                    .anyRequest().permitAll()
                    .and()
                .exceptionHandling()
                    .accessDeniedHandler(new CustomAccessDeniedHandler())
//                    .authenticationEntryPoint()
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .loginProcessingUrl("/clickLogin")
                    .successHandler(new AuthenticationSuccessHandler() {
                        @Override
                        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                            response.setContentType("application/json;charset=UTF-8");
                            PrintWriter pw = response.getWriter();
                            Res result = new Res(true, "登录成功");
                            String s = JSON.toJSONString(result);
                            pw.write(s);
                            pw.close();
                        }
                    })
                    .failureHandler(new AuthenticationFailureHandler() {
                        @Override
                        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
                            response.setContentType("application/json;charset=UTF-8");
                            PrintWriter pw = response.getWriter();
                            Res result = new Res(false, "账号密码错误");
                            String s = JSON.toJSONString(result);
                            pw.write(s);
                            pw.close();
                        }
                    })
                    .permitAll()
                    .and()
                .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessUrl("/login")
                    .and()
                    //允许页面镶嵌
                .headers()
                .frameOptions().sameOrigin()
                .httpStrictTransportSecurity().disable()
                .and()
                .csrf()
                .disable()
                .headers().frameOptions().disable();

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

我们还需要注入一个方法

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

        auth
                .userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这段代码表示security通过userDetails来校验用户登录,当然也有通过内存信息来校验登录的

        auth
                .inMemoryAuthentication().withUser("user").password("123456").roles("ADMIN");
  • 1
  • 2

除此之外,我们还要特别注意security验证密码的时候是必须加密,security验证密码的过程是这样的:

将用户输入的密码进行加密,加密后与从userDetails详细用户信息中获取的用户密码进行核对,所以userDetails中的密码必须是加密过的,也就是说数据库中的密码我们需要加密,一般在注册的时候先对密码加密再存入数据库

我们可以自定义选择加密方式,我们一般使用的是BCryptPasswordEncoder

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
  • 1
  • 2
  • 3
  • 4

然后在这个地方配置加密规则()

        auth
                .userDetailsService(userService).passwordEncoder(passwordEncoder());
  • 1
  • 2

权限控制

我们在登录之后,一般都会获取该用户的相关信息,包括权限信息,所以我们在实体类中需要一个有关权限的属性,并且是集合类型,因为一个用户可能有多个权限,在实体类中我们可以加入以下属性与方法

    private Collection<SimpleGrantedAuthority> authorities;


    @Override
    public Collection<SimpleGrantedAuthority> getAuthorities() {
        return authorities;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在mapper.xml中,我们通过联表查询用户的所有信息,特别要注意的是我们必须要获取用户的用户名与密码,

因为前面所讲的登录认证需要用到,然后我们配置权限这个属性的时候,注意在collection标签中加上notNullColumn这个属性,

因为如果某些用户的权限为空的话,security可能会缓存上一个用户的权限信息

    <select id="getUserAndRoles" resultMap="Role" parameterType="String" >
SELECT u.*,r.role_name from tbl_user u
left join tbl_user_role ur  on u.id = ur.user_id
left join tbl_role r on ur.role_id=r.id
where u.username=#{username}
    </select>

    <resultMap id="Role" type="com.tty.bean.User">

        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="name" property="name"/>

        <collection property="authorities" ofType="org.springframework.security.core.authority.SimpleGrantedAuthority" notNullColumn="role_name">
            <result column="role_name" property="role"/>
        </collection>
    </resultMap>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

并且我们要保证security获取的权限名字是以ROLE_开头,我们可以在数据库中添加权限的时候直接加上ROLE_,或者我们可以自定义一个

GrantedAuthority的实现类(这个实现类可以模仿SimpleGrantedAuthority这个类来写,如以下自定义实现类的代码,这样就可以让security给我们的权限自动加上ROLE_

@Data
public class CustomSimpleAuthority implements GrantedAuthority {
    private static final long serialVersionUID = 530L;
    private int id;
    private String authority;
    private String name;

    public CustomSimpleAuthority(String authority) {
        Assert.hasText(authority, "A granted authority textual representation is required");
        this.authority = authority;
    }
    @Override
    public String getAuthority() {
        return "ROLE_"+this.authority;
    }
    @Override
    public String toString() {
        return name;
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

,然后将UserDetails中的authorities类型的泛型改为该实现类

例如:

    private Collection<CustomSimpleAuthority> authorities;
  • 1

配置 好权限之后,我们可以在某些接口的方法上使用相关注解,例如@RolesAllowed,从而使得该接口有特定权限才能访问,

如以下代码,表示admin页面只有具有ROLE_ADMIN权限的用户才可以访问

    @RolesAllowed({"ROLE_ADMIN"})
    @RequestMapping("/admin")
    public String admin(){
        return "admin";
    }
  • 1
  • 2
  • 3
  • 4
  • 5

权限控制我们也需要在自定义的security配置类WebSecurityConfig中配置有关异常处理的信息,如下



 http
     .exceptionHandling()
     .accessDeniedHandler(new SimpleAccessDeniedHandler())//权限异常处理
     .authenticationEntryPoint(new SimpleAuthenticationEntryPoint())//认证异常处理

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这些配置好后,如果我们使用没有ROLE_ADMIN权限的用户访问这个admin页面

,会出现AccessDeniedException异常并且依旧可以访问该admin页面,因为我们没有进行全局异常捕获异,我们可以利用SpringMVC的全局异常捕获,l如下代码:

//使用该注解让springmvc 统一捕捉异常, 并且作出处理
@RestControllerAdvice
public class BookExceptionAdvice {

    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(value = AccessDeniedException.class)
    public Res AccessDeniedException(AccessDeniedException e){
        e.printStackTrace();
        return new Res(false,e.getMessage());
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

WebSecurityConfig中配置后,再通过全局异常捕获以后,我们基本可以实现权限控制

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/481618
推荐阅读
相关标签
  

闽ICP备14008679号