spring boot + security 并实现自定义登陆

  |   0 评论   |   242 浏览

一、前言

前段时间开始着手一个项目,涉及到了一些简单的权限控制。我呢又有点作,又不喜欢简单的用个过滤器就完事。所以我就想到了spring security这个框架,想到了是一回事,不会又是一回事。不会能怎么办呢?找资料啊!!下面开始正文。

1、配置

首先在pom.xml文件里面引入依赖

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

建立security配置类

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsServiceImpl userDetailService() {
        return new UserDetailsServiceImpl();
    }

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider);//自定义用户认证器
        auth.userDetailsService(userDetailService()).passwordEncoder(new BCryptPasswordEncoder(10));
    }

    @Override
    public void configure(WebSecurity web) {
        // 忽略URL
        web.ignoring().antMatchers("/assets/**", "/login?error", "/clients", "/css", "/js", "/downloads", "/s/**", "/captcha/default", "/resetPassword","/lang/**","/robots.txt");//请不要将用户登录(认证)url添加到这里面,否则会导致security无法处理认证。
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers()
                .frameOptions()//解决不允许显示在iframe的问题
                .sameOrigin()
                .httpStrictTransportSecurity()
                .disable().and()
                .authorizeRequests()
                .mvcMatchers("/login", "/register").permitAll()//登录注册页面,不登录也能访问
                .mvcMatchers("/admin").hasRole("ADMIN")//admin页面必需要admin权限才能访问
                .anyRequest().authenticated() //任何请求,登录后可以访问
                .and()
                .formLogin()
                .loginPage("/login")
                .successForwardUrl("/index")//登录成功后跳转的url
                .defaultSuccessUrl("/")//默认登陆成功后跳转的url
                .failureUrl("/login?error")//登录失败跳转的url
                .permitAll() //登录页面用户任意访问
                .and()
                .logout().permitAll().invalidateHttpSession(true).and()
                .sessionManagement().invalidSessionUrl("/login").and()
                //只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面
            	//要实现用户只能登陆一个账号,user对象必须重写 equals(),hashCode()方法
                .sessionManagement().maximumSessions(1).expiredUrl("/login");
    }
}

基本上的配置就结束了。

2、自定义认证处理器

建立自定义用户认证处理器时,用户类需要实现UserDetails接口

需要建立一个安全用户认证service实现UserDetailsService并实现所有方法

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.findByUserName(username);//用户查询方式(这里并不需要密码)
        if (user != null) {
            return user;
        } else {
            throw new UsernameNotFoundException("user:" + username + " do not exist!");
        }
    }
}

新建一个类,实现AuthenticationProvider接口,并重写所有方法

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String inputName = authentication.getName();
        String inputPassword = authentication.getCredentials().toString();

        // userDetails为数据库中查询到的用户信息
        User userDetails = (User) userDetailsService.loadUserByUsername(inputName);
        //认证用户逻辑省略。。。

        if (userDetails.getIsAdmin() == 1 ){
            //因为项目表设计缘故必须手动认证用户权限
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            //手动给有权限的用户添加security能识别的认证
            authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            userDetails.setAuthorities(authorities);
        }
        return new UsernamePasswordAuthenticationToken(inputName, inputPassword, userDetails.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        // 这里不要忘记,和UsernamePasswordAuthenticationToken比较
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

好了,security的基本使用就结束了。

评论