• Spring Boot + Spring Security + Vue实现前后端分离登录认证


    本文参考地址:https://blog.csdn.net/I_am_Hutengfei/article/details/100561564/

    上述地址中作者开发了后端的登录认证功能,但是对于普通的不涉及权限的前后端分离登录就略有不同,这里仅讲述与上述地址中作者描述不同的地方

    LoginService.java
    import org.mybatis.spring.SqlSessionTemplate;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Service;
    import top.gerritchang.daily.menu.entity.UserEntity;
    import top.gerritchang.daily.menu.mybatis.LoginMapper;
    
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.Collection;
    
    @Service
    public class LoginService implements UserDetailsService {
    
        @Resource
        private SqlSessionTemplate sqlSessionTemplate;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            LoginMapper loginMapper = sqlSessionTemplate.getMapper(LoginMapper.class);
            UserEntity userEntity = loginMapper.getUserByUName(username); //UserEntity是用户基本信息,后面调用的是自己的Mapper层查询用户的接口
            if (userEntity == null) {
                throw new UsernameNotFoundException("用户名不存在");
            }
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); //这个地方随便赋值一个角色就好了
            userEntity.setAuthorities(authorities);
            SecurityContextHolder.setContext(SecurityContextHolder.getContext());
            return userEntity;
        }
    }
    

      UserEntity.java

    import java.util.Collection;
    
    public class UserEntity implements UserDetails {
        private String id;
        private String username;
        private String password;
        private Collection<? extends GrantedAuthority> authorities;
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
            this.authorities = authorities;
        }
    
        public String getUsername() {
            return username;
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @Override
        public boolean isEnabled() {
            return true;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return authorities;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    

      CustomizeFilterInvocationSecurityMetadataSource.java

    import java.util.Collection;
    
    @Component
    public class CustomizeFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
    
        AntPathMatcher antPathMatcher = new AntPathMatcher();
    
        @Override
        public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
            //获取请求地址
    //        String requestUrl = ((FilterInvocation) o).getRequestUrl();
    //        //查询具体某个接口的权限
    //        List<SysPermission> permissionList =  sysPermissionService.selectListByPath(requestUrl);
    //        if(permissionList == null || permissionList.size() == 0){
    //            //请求路径没有配置权限,表明该请求接口可以任意访问
    //            return null;
    //        }
    //        String[] attributes = new String[permissionList.size()];
            String[] attributes = new String[]{"ROLE_ADMIN"}; //这里和第一个文件的内容相同即可
    //        for(int i = 0;i<permissionList.size();i++){
    //            attributes[i] = permissionList.get(i).getPermissionCode();
    //        }
            return SecurityConfig.createList(attributes);
        }
    
        @Override
        public Collection<ConfigAttribute> getAllConfigAttributes() {
            return null;
        }
    
        @Override
        public boolean supports(Class<?> aClass) {
            return true;
        }
    }
    

      SecurityConfiguration.java

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.ObjectPostProcessor;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
    import top.gerritchang.daily.auth.*;
    import top.gerritchang.daily.menu.service.LoginService;
    
    import javax.annotation.Resource;
    
    /**
     * 这个是前后端不分离项目中登录
     */
    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Resource
        private LoginService loginService;
    
        @Resource
        private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    
        @Resource
        private MyAuthenticationFailHandler myAuthenticationFailHandler;
    
        @Resource
        private CustomizeLogoutSuccessHandler logoutSuccessHandler;
    
        @Resource
        private CustomizeAuthenticationEntryPoint authenticationEntryPoint;
    
        @Resource
        private CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;
    
        @Resource
        private CustomizeAbstractSecurityInterceptor securityInterceptor;
    
        //访问决策管理器
        @Resource
        CustomizeAccessDecisionManager accessDecisionManager;
    
        //实现权限拦截
        @Resource
        CustomizeFilterInvocationSecurityMetadataSource securityMetadataSource;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(loginService).passwordEncoder(passwordEncoder());
        }
    
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.cors().and().csrf().disable();
            httpSecurity
                    .cors()
                    .and()
                    .authorizeRequests()
                    .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                        @Override
                        public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                            o.setAccessDecisionManager(accessDecisionManager);//决策管理器
                            o.setSecurityMetadataSource(securityMetadataSource);//安全元数据源
                            return o;
                        }
                    })
                    .and().logout().logoutSuccessUrl("/logout")
                    .logoutSuccessHandler(logoutSuccessHandler)//登出成功处理逻辑
                    .deleteCookies("JSESSIONID")
                    .and()
                    .formLogin()
                    .loginProcessingUrl("/login")
                    .successHandler(myAuthenticationSuccessHandler)
                    .failureHandler(myAuthenticationFailHandler)
                    .permitAll()
                    .and().exceptionHandling()
                    .authenticationEntryPoint(authenticationEntryPoint)
                    .and().sessionManagement()
                    .maximumSessions(1)//同一账号同时登录最大用户数
                    .expiredSessionStrategy(sessionInformationExpiredStrategy);
            httpSecurity.addFilterBefore(securityInterceptor, FilterSecurityInterceptor.class);
        }
    
        @Bean
        PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
    }
    

      其他在SecurityConfiguration里面用到的类与引用地址给出的一致即可,部分名字可能有出入,以引用地址为主即可

    这时,调用axios登录的地址就变成了上述代码段里配置的"/login",那么axios去登录的话需要这样写:

    let params = new FormData();
    params.append("username", username);
    params.append("password", password);
    let config = {
          headers: {"Content-Type": "application/x-www-form-urlencoded"}
    };
    let url = "http://localhost:8081/login";
    axios.post(url, params, config)
    

      这时,虽然可以正常登录了,但是呢,当你访问其他的资源的时候会报角色错,角色就变成了"ROLE_ANONYMOUS"。这时我们需要在前端里修改一下,让axios请求的时候带上cookies即可,具体代码如下:

    import axios from 'axios'
    axios.defaults.withCredentials = true;
    
  • 相关阅读:
    Servlet和Filter的url匹配
    iterator的用法
    python学习笔记
    python的序列之列表
    java开发实战学习笔记3
    java学习笔记4
    Java Java集合
    Struts2中的几个符号
    DbHelper.cs
    做word,excel时需要引用com
  • 原文地址:https://www.cnblogs.com/gerritchang/p/16002455.html
Copyright © 2020-2023  润新知