SpringSecurity-认证和授权

表单登录

单体应用

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
    //5.0以后默认使用非明文密码,如下方式使用已经过时的明文密码验证
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }
    
    
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests() //返回一个url拦截注册器,通过他来匹配需要拦截的请求
                .anyRequest().authenticated() //所有请求都要被拦截进行认证
                .and()//回到HttpSecurity http
            .ignoring().antMatchers("js/**","css/**")//静态自愿放行
            	.and()
            .formLogin() //返回一个SpringScurity提供的表单认证配置器
                .loginPage("/myLogin.html") //指定自定义登录页,同时会以/myLogin.html注册一个Post路由,用于接收登录请求
                .loginProcessingUrl("/login")//代替默认注册的验证路由,使用自定义路由接收登陆请求
                .successForwardUrl("/index.html")//登录成功的跳转页面
                .failureForwardUrl("/error.html")//登录失败的跳转页面
                .usernameParameter("user")//替换默认接收用户名参数(username)为user
                .passwordParameter("pwd")//替换默认接收密码参数(password)为pwd
                .permitAll()//对操作路由进行放行
                .and()
            .csrf().disable();//跨站请求伪造防护功能,当继承WebSecurityConfigurerAdapter时会默认开启csrf()方法
    }
}

前后端分离应用

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests() //返回一个url拦截注册器,通过他来匹配需要拦截的请求
                .anyRequest().authenticated() //所有请求都要被拦截进行认证
                .and()//回到HttpSecurity http
            .formLogin() //返回一个SpringScurity提供的表单认证配置器
                .loginPage("/myLogin.html") //指定自定义登录页,同时会以/myLogin.html注册一个Post路由,用于接收登录请求
                .loginProcessingUrl("/login")//代替默认注册的验证路由,使用自定义路由接收登陆请求
                .successForwardUrl("/index.html")//登录成功的跳转页面
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=UTF-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{"error_code":"0","message":"登录成功"}");
                    }
                })//登录成功返回json数据
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=UTF-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{"error_code":"401","message":"登录验证失败"}");
                    }
                })//登录失败返回json数据
                .usernameParameter("user")//替换默认接收用户名参数(username)为user
                .passwordParameter("pwd")//替换默认接收密码参数(password)为pwd
                .permitAll()//对操作路由进行放行
                .and()
            .csrf().disable();//跨站请求伪造防护功能,当继承WebSecurityConfigurerAdapter时会默认开启csrf()方法
    }
}

授权

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests() //返回一个url拦截注册器,通过他来匹配需要拦截的请求
                .anyRequest().authenticated() //所有请求都要被拦截进行认证
                .antMatchers("/admin/api/**").hasAnyRole("ADMIN")//admin角色用户可以访问限制
                .antMatchers("/user/api/**").hasAnyRole("USER")//user角色用户访问限制
                .antMatchers("/app/api/**").permitAll()//所有角色用户都可访问
                .and()//回到HttpSecurity http
            .formLogin() //返回一个SpringScurity提供的表单认证配置器
                .loginPage("/myLogin.html") //指定自定义登录页,同时会以/myLogin.html注册一个Post路由,用于接收登录请求
                .loginProcessingUrl("/login")//代替默认注册的验证路由,使用自定义路由接收登陆请求
                .successForwardUrl("/index.html")//登录成功的跳转页面
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=UTF-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{"error_code":"0","message":"登录成功"}");
                    }
                })//登录成功返回json数据
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=UTF-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write("{"error_code":"401","message":"登录验证失败"}");
                    }
                })//登录失败返回json数据
                .usernameParameter("user")//替换默认接收用户名参数(username)为user
                .passwordParameter("pwd")//替换默认接收密码参数(password)为pwd
                .permitAll()//对操作路由进行放行
                .and()
            .csrf().disable();//跨站请求伪造防护功能,当继承WebSecurityConfigurerAdapter时会默认开启csrf()方法
    }
}

antMatchers()是一个采用ANT模式的URL匹配器。

  • 匹配任意单个字符 *
  • 匹配任意多个字符 **

认证和授权

基于内存的多用户支持

实现自定义的UserDetailsService,任何实现UserDetailsService接口的对象都可以作为验证数据源

InMemoryUserDetailsManager是UserDetailsService接口中的一个实现类,它将用户数据源寄存在内存里,这里仅仅调用createUser()生成两个用户,并赋予相应的角色。

    @Bean
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        inMemoryUserDetailsManager.createUser(User.withUsername("liuhui").password("12121").roles("ADMIN").build());
        inMemoryUserDetailsManager.createUser(User.withUsername("zhujie").password("12121").roles("USER").build());
        return inMemoryUserDetailsManager;
    }

基于默认数据库模型的多用户支持

JdbcUserDetailsManager帮助我们以JDBC的方式对接数据库和Spring Security,它设定了一个默认的数据库模型。

JdbcUserDetailsManager需要两个表,User表和authorities表,用来描述角色和权限的关联

Users:用户名、密码、是否可用

authorities:用户名、权限

相对于基于内存的方式很相似,主要区别是相当于把用户信息保存到了数据库中,比如creatUser相当于在数据库中执行

insert into users(username,password,enabled) values(?,?,?)

    @Autowired
    private DataSource dataSource;

    @Bean
    public UserDetailsService userDetailsService(){
        JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager();
        jdbcUserDetailsManager.setDataSource(dataSource);

        jdbcUserDetailsManager.createUser(User.withUsername("liuhui").password("12121").roles("ADMIN").build());
        jdbcUserDetailsManager.createUser(User.withUsername("zhujie").password("12121").roles("USER").build());
        return jdbcUserDetailsManager;
    }

基于自定义数据库模型的认证和授权

编写一个用户实体实现UserDetails

public class User implements UserDetails {

    private Long id;//用户id
    private String username;//用户名
    private String password;//密码
    private String roles;//权限信息
    private boolean enbled;//是否启用
    private List<GrantedAuthority> authorities;


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return null;
    }

    @Override
    public boolean isAccountNonExpired() { //是否过期
        return true;
    }

    @Override
    public boolean isAccountNonLocked() { //是否锁定
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() { //用户凭证是否过期
        return true;
    }

    @Override
    public boolean isEnabled() {
        return enbled;
    }
    //set//get

编写通过用户名查找用户的mapper

public interface UserMapper {
    @Select("SELECT * FROM users WHERE username=#{username}")
    User findByUserName(@Param("username") String username);
}

编写MyUserDetailsService并实现UserDetailsService

@Service
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //从数据库尝试读取该用户
        User user = userMapper.findByUserName(username);
        //用户不存在,抛出异常
        if(user == null){
            throw new UsernameNotFoundException("用户不存在!");
        }
        //将数据库形式的roles解析为UserDetails的权限集
        //AuthorityUtils.commaSeparatedStringToAuthorityList是SpringSecurity提供的,该方法用于将逗号隔开的权限集字符串切割成可用权限集合
        //也可自己实现
        user.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(user.getRoles()));
        return user;
    }
}

原文地址:https://www.cnblogs.com/luckyhui28/p/13550576.html