springSecurity+vue权限控制(1)

       之前都是自个实现登录拦截、用户验证,自从发现了研究springSecurity这个框架之后,爱不释手,基本上权限+验证方面的操作都可以完成,是spring中一个重量级的安全校验框架。

       很多人抱怨springSecurity的api太复杂,其实不然,当你了解它的流程操作时,用起来相当顺手,搭配springboot可快速搭建一个有权限控制级别的项目。

      在使用springSecurity之前,我们先来认识一下它的核心类。

Authentication

      Authentication是表示用户信息的一个接口,通过它可封装一些用户登录认证的对象,用户认证成功后,又会生成一个信息更加全面,包括用户所拥有的角色等信息的Authentication对象,然后把它保存在SecurityContextHolder 所持有的 SecurityContext 中,供后续的程序进行调用,如访问权限的鉴定等。

SecurityContextHolder

      根据以上所知,它是一个用来保存SecurityContext的一个类,而SecurityContext中又存储着用户信息。它含有很多静态方法,如getContext、setContext、clearContext来对SecurityContext进行操作。

AuthenticationManager 和 AuthenticationProvider

      AuthenticationManager 是一个用来处理认证(Authentication)请求的接口。在其中只定义了一个方法 authenticate(),该方法只接收一个代表认证请求的 Authentication 对象作为参数,如果认证成功,则会返回一个封装了当前用户权限等信息的 Authentication 对象进行返回。

     AuthenticationManager 的默认实现是 ProviderManager,它不自己处理请求,而是通过委托机制给其配置的AuthenticationProvider 列表,然后会依次使用每一个 AuthenticationProvider 进行认证,如果有一个 AuthenticationProvider 认证后的结果不为 null,则表示该 AuthenticationProvider 已经认证成功,之后的 AuthenticationProvider 将不再继续认证

UserDetailsService

        认识这个接口之前我们先来看一下UserDetails接口,UserDetails中定义了用户的账户、密码、权限等信息,可通过实现该接口中的方式自行定义用户信息类。而UserDetailsService中只有一个方法loadUserByUsername(),该方法返回的便是一个UserDetails对象。这个方法主要是对web传来的用户信息进行验证操作,验证成功便返回用户所属的UserDetails信息。用户验证不通过则抛出UsernameNotFoundException异常。

 现在我们来开始搭建我们的springSecurity。

首先,定义好我们的用户信息类User

@Entity
@Table(name = "SISE_USER")
public class User extends BaseEntity{
    @Column(name="USER_USERNAME",length=400)
    private String username;
    @Column(name="USER_ACCOUNT",length=400)
    private String account;
    @Column(name="USER_PASSWORD",length = 400)
    private String password;
    @Column(name="USER_EMAIL",length = 400)
    private String email;
    @Column(name = "USER_PHONE",length = 400)
    private String phone;
    @ManyToMany(fetch = FetchType.EAGER, targetEntity = Role.class)
    @JoinTable(name = "TT_USER_ROLE",joinColumns = @JoinColumn(name = "USER_ID"),inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
    private Set<Role> roles = new LinkedHashSet<>();

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
}

 然后创建一个SecurityUser类来继承这个User和实现Usertails接口

public class SecurityUser extends User implements UserDetails {

    private static final long serialVersionUID = 1L;

    public SecurityUser(User suser) {

        if (suser != null)

        {

            this.setsId(suser.getsId());

            this.setUsername(suser.getUsername());

            this.setAccount(suser.getAccount());

            this.setEmail(suser.getEmail());

            this.setPassword(suser.getPassword());


            this.setRoles(suser.getRoles());

        }

    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        Set<Role> roles = super.getRoles();
        if(roles != null){
            for(Role role : roles){
                SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getRoleName());
                authorities.add(authority);
            }
        }
        return authorities;
    }

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

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

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

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

 到了这里,我们的用户信息基本定义完成。

接下来我们来实现UserDetailsService接口,我们创建一个CustomerUserService来实现它。

@Component
public class CustomUserDetailsService implements UserDetailsService{

    @Autowired
    private UserService userService;

    @Override
    public UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {
        User user = userService.findByAccount(account);
        if(user == null){
            throw new UsernameNotFoundException("Username :" + account + "not found");
        }
        SecurityUser securityUser = new SecurityUser(user);
        return securityUser;
    }
}

记得使用@Component把它注册为组件,便于spring进行实例化。

接下来就是要对springSercurity进行配置和使用,我们创建一个WebSecurityConfig继承WebSecurityConfiguConfigurerAdater

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

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.authorizeRequests().anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/login_p")
                .loginProcessingUrl("/login")
                .usernameParameter("account")
                .passwordParameter("password")
                .permitAll()
                .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();

                StringBuffer sb = new StringBuffer();
                sb.append("{\"status\":\"error\",\"msg\":\"");
                if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
                    sb.append("用户名或密码输入错误,登录失败!");
                } else if (e instanceof DisabledException) {
                    sb.append("账户被禁用,登录失败,请联系管理员!");
                } else {
                    sb.append("登录失败!");
                }
                sb.append("\"}");
                out.write(sb.toString());
                out.flush();
                out.close();
            }
        }).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();
                SecurityUser user = (SecurityUser) SecurityContextHolder.getContext()
                        .getAuthentication()
                        .getPrincipal();
                Set<Menu> menus = new HashSet<>();
                for(Role role : user.getRoles()){
                    menus.addAll(role.getMenus());
                }
                ArrayNode datas = JsonUtils.createArrayNode();
                ObjectNode data;
                data = datas.addObject();
                data.put("account",user.getAccount());
                data.put("userId",user.getsId());
                data.put("username",user.getUsername());
                ObjectMapper objectMapper = new ObjectMapper();
                String s = "{\"status\":\"success\",\"msg\":" + objectMapper.writeValueAsString(datas) + "}";
                out.write(s);
                out.flush();
                out.close();
            }
        }).and().logout().permitAll().and().csrf().disable();
    }

    @Autowired
    public void globalConfigure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(customUserDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();

    }

    @Bean
    public CustomUserDetailsService customUserDetailsService(){
        return new CustomUserDetailsService();
    }
}
http.authorizeRequests().anyRequest().authenticated()
        .and()
        .formLogin().loginPage("/login_p")
        .loginProcessingUrl("/login")
        .usernameParameter("account")
        .passwordParameter("password")
        .permitAll()

loginPage方法指定登录界面,因为我们使用vue前后端分离,所以这里可以不用指定,可直接去掉

loginprocessingUrl方法设置登录接口,前端登录访问的接口,默认为/login。

usernameParameter和passwordParameter便是接口所需的参数。

 

.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();

                StringBuffer sb = new StringBuffer();
                sb.append("{\"status\":\"error\",\"msg\":\"");
                if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
                    sb.append("用户名或密码输入错误,登录失败!");
                } else if (e instanceof DisabledException) {
                    sb.append("账户被禁用,登录失败,请联系管理员!");
                } else {
                    sb.append("登录失败!");
                }
                sb.append("\"}");
                out.write(sb.toString());
                out.flush();
                out.close();
            }

该方法主要是登录失败之后所进行的操作

.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();
                SecurityUser user = (SecurityUser) SecurityContextHolder.getContext()
                        .getAuthentication()
                        .getPrincipal();
                Set<Menu> menus = new HashSet<>();
                for(Role role : user.getRoles()){
                    menus.addAll(role.getMenus());
                }
                ArrayNode datas = JsonUtils.createArrayNode();
                ObjectNode data;
                data = datas.addObject();
                data.put("account",user.getAccount());
                data.put("userId",user.getsId());
                data.put("username",user.getUsername());
                ObjectMapper objectMapper = new ObjectMapper();
                String s = "{\"status\":\"success\",\"msg\":" + objectMapper.writeValueAsString(datas) + "}";
                out.write(s);
                out.flush();
                out.close();
            }
        })

登录成功后所进行的操作。

在登录中,我们还需要对密码进行加密,springSecurity有很多hash加密方法,在这里我们使用BCryptPasswordEncoder对密码进行加密

@Autowired
public void globalConfigure(AuthenticationManagerBuilder auth) throws Exception{
    auth.userDetailsService(customUserDetailsService())
            .passwordEncoder(passwordEncoder());
}

@Bean
public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();

}

 

 

到了这一步,我们就基本完成了一个登录验证的功能,后面我会用vue+springboot完成一个拥有权限控制的系统。

### 回答1: Spring SecurityVue是两个不同的技术,可以结合使用来实现Web应用程序的安全性。 Spring Security是一个基于Spring框架的安全性解决方案,它提供了一系列的安全性功能,包括身份验证、授权、会话管理等。Vue是一个流行的JavaScript框架,用于构建现代Web应用程序的用户界面。 结合使用Spring SecurityVue可以实现前后端分离的Web应用程序,并且保证应用程序的安全性。具体实现方式可以使用Spring Security提供的RESTful API进行身份验证和授权,同时使用Vue来构建用户界面。这样可以使得应用程序的前端和后端分离,提高开发效率和应用程序的可维护性。 ### 回答2: Spring Security是一个功能强大、灵活的安全框架,它为基于Java的应用程序提供了一系列的安全服务。而Vue.js是一种用于构建用户界面的渐进式JavaScript框架。 Spring SecurityVue.js可以很好地结合使用,以实现更安全和友好的前后端交互。一般情况下,前端框架(如Vue.js)负责用户界面的展示和用户交互,而后端框架(如Spring Security)负责验证和保护后端资源。 具体而言,Spring Security提供了各种身份验证和授权机制,可以帮助我们验证用户的身份、限制访问资源和保护敏感信息。它可以通过配置文件或自定义的代码来定义访问规则,以确保只有经过认证和授权的用户才能访问受保护的资源。Spring Security还提供了会话管理、密码加密和跨站点请求伪造(CSRF)防护等功能,以提高应用程序的安全性。 而Vue.js则可以配合Spring Security来实现前端的用户界面和用户交互效果。通过Vue.js可以轻松构建交互性的用户界面,并结合Spring Security权限控制功能实现更细粒度的权限管理。例如,可以根据用户角色动态显示或隐藏某些界面元素,以实现不同用户权限的差异化显示。 总之,Spring SecurityVue.js的结合可以帮助我们构建安全可靠的Java web应用程序。Spring Security提供了强大的后端安全服务,而Vue.js则提供了灵活、高效的前端开发框架,二者搭配使用可以实现更好的用户体验和数据安全性。 ### 回答3: Spring Security是一个基于Java的开源框架,用于在Java Web应用中实现安全身份验证和授权管理。它提供了一系列的安全性功能,包括用户身份验证、用户角色和权限的定义、资源的访问控制等。 而Vue是一个前端开发框架,与Spring Security结合使用可以实现前后端分离的开发模式。在这种模式下,前端使用Vue进行页面展示和交互逻辑的处理,后端使用Spring Security进行用户身份验证和权限控制。 使用Spring SecurityVue,可以实现以下功能: 1. 用户注册和登录:Spring Security提供了强大的用户认证机制,可以对用户进行身份验证,并且可以使用Vue处理用户注册和登录的界面。 2. 权限控制Spring Security定义了用户角色和权限的概念,可以通过配置文件或数据库对用户的访问权限进行控制Vue可以根据用户权限隐藏或显示不同的功能模块。 3. 跨域访问控制Vue通常与后端分离部署,可能存在跨域访问问题。通过Spring Security的配置可以实现对跨域请求的控制,保护Web应用的安全性。 4. 前后端数据交互:Vue通过RESTful API与后端进行数据交互,Spring Security可以拦截请求,验证用户的身份以及访问权限,并返回数据给Vue进行展示。 Spring SecurityVue的结合可以实现前后端的分离开发,提高开发效率和安全性。通过合理的配置和设计,可以实现灵活的权限控制和用户管理。同时,这种组合还可以让开发人员专注于各自的领域,提高开发效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值