springboot使用session登录与使用springsecurity实现登录(前后端分离,前端使用的是vue)

登录

使用session登录

  • 注解和方法的依赖包就不写了,找不到可以自己百度。
  1. 配置拦截器(设置你的登陆界面)
@Configuration
public class MyMvcConfig implements WebMvcConfigurer{
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginHandlerInterceptor())
                .addPathPatterns("/**").excludePathPatterns("/user/login");
    }
}
  1. 配置corsFilter过滤器
    tips:corsFilter配置的是全局过滤器,会在项目运行的时候配置完成。需要主要注意的是你后续的配置(比如设置请求头)可能会把这里的设置覆盖。
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOriginPattern("*");
        config.setAllowCredentials(true);
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(configSource);
    }
}
  1. 重写prehandle
/**
 * 登录拦截器
 * author: wuzj
 */
public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //登陆成功之后应该有用户的session
        Object session = request.getSession().getAttribute("LoginUser");
//        System.out.println(session);
        if (session == null) {  //没有登陆
            //重置response
            response.reset(); 
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json;charset=UTF-8");
            //设置编码格式
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
            response.addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
            response.addHeader("Access-Control-Max-Age", "3600");
            String origin = request.getHeader("Origin");
            response.setHeader("Access-Control-Allow-Origin", origin);
            response.setHeader("Access-Control-Allow-Credentials", "true"); 
            //要返回前端的数据
            PrintWriter printWriter=response.getWriter();
            printWriter.write("{\"status\":403}"); 
            printWriter.flush();
            printWriter.close();
//            response.sendRedirect(request.getContextPath() + "/user/login"); 
            return false;
        } else {
            return true;
        }
    }
}
  1. 登陆函数
  • userMapper里的获取用户名密码这里就不赘述了
/**
 * 登录控制器
 * author:wuzj
 */
@RestController
@Slf4j
public class LoginController {  

    @Autowired
    private UserMapper userMapper;

    @CrossOrigin
    @RequestMapping(value = "/user/login", method = RequestMethod.POST)
    public Result login(@RequestParam("username") String userName, 
    					@RequestParam("password") String password,
                        HttpServletRequest request, HttpServletResponse response) {

        //session方式
        HttpSession session = request.getSession();
        session.setAttribute("LoginUser", userName);    //session中存的值
        User user = userMapper.getUserByName(userName);
        if (user == null) {
            System.out.println("用户名为空!!");
        }
        else if (password.equals(user.getPassword())) {
            return new Result(ResponseCode.successCode, "登录成功");
        } else {
            return new Result(ResponseCode.passwordErrorCode, "密码错误");
        }
        return new Result(ResponseCode.passwordErrorCode, "用户名或密码错误");
    }

    @RequestMapping(value = "/user/loginOut", method = RequestMethod.POST)
    public void loginOut(HttpSession session, HttpServletRequest request, HttpServletResponse response) {
        session.removeAttribute("LoginUser");
        session.invalidate();
    }
}

spring-security登录

  1. 引入依赖
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
  1. 配置Spring Security配置类
/**
 * Spring Security配置类
 */
@EnableGlobalMethodSecurity(prePostEnabled = true)  //开启注解
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsServiceImpl;

    /**
     * 用户认证配置
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /**
         * 指定用户认证时,默认从哪里获取认证用户信息
         */
        auth.userDetailsService(userDetailsServiceImpl);

//        auth.inMemoryAuthentication()
//                .withUser("test01")
//                .password("123456").roles("admin");
    }

    /**
     * Http安全配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        /**
         * 表单登录:使用默认的表单登录页面和登录端点/login进行登录
         * 退出登录:使用默认的退出登录端点/user/loginOut退出登录
         * 记住我:使用默认的“记住我”功能,把记住用户已登录的Token保存在内存里,记住30分钟
         * 注意:Controller中也对URL配置了权限,如果WebSecurityConfig中和Controller中都对某文化URL配置了权限,则取较小的权限
         */
        http
                .formLogin()        //配置表单登录
//                .loginPage("/login.html")  //自定义登录页面,默认/login
				.loginProcessingUrl("/user/login")    //登陆成功跳转页面
                .successHandler((request,response,authentication) -> {    //使用lamda表达式处理登录成功的处理
                    Map<String,Object> map = new HashMap<>();
                    map.put("status",200);
                    map.put("message","登录成功");
                    map.put("data",authentication);       //认证信息
//                    map.put("data","security登陆成功");
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter out = response.getWriter();
                    JSONObject json = new JSONObject(map);
                    out.write(json.toJSONString());
                    out.flush();
                    out.close();
                })
                .failureHandler((request,response,ex) -> {	//认证失败处理
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                    PrintWriter out = response.getWriter();
                    Map<String,Object> map = new HashMap<>();
                    map.put("status",201);
                    if (ex instanceof UsernameNotFoundException || ex instanceof BadCredentialsException) {
                        map.put("status",401);
                        map.put("message","用户名或密码错误");
                    } else if (ex instanceof DisabledException || ex instanceof InternalAuthenticationServiceException) {
                        response.setStatus(200);
                        map.put("status",402);
                        map.put("message","账户被禁用!!");
                    } else {
                        map.put("message","登录失败!");
                    }
                    JSONObject json = new JSONObject(map);
                    out.write(json.toJSONString());
                    out.flush();
                    out.close();
                })
                .permitAll()
                .and()
                .authorizeRequests()
//                .antMatchers("/admin/**").access("hasRole('ADMIN')")  //所有URL以"/admin"开头的用户必须拥有角色"ADMIN"才能访问
//                .antMatchers("/user/**").access("hasRole('USER')")
				.requestMatchers(CorsUtils::isPreFlightRequest).permitAll() // 放过预检请求
                .antMatchers("/v2/api-docs","/swagger-resources/**","/swagger-ui.html", "/webjars/**").permitAll()		//允许swagger不带身份信息进入
                .anyRequest().authenticated()   //对任何一个请求,都需要认证
//                .antMatchers("/login","/login_page","/user/login")
//                .permitAll()      //过滤不需要认证的路径
                .and()
                .csrf().disable()
                .cors()
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(new AuthenticationEntryPoint() {      //重写登陆失效跳转
                    @Override
                    public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException authException) throws IOException, ServletException {
                        resp.setContentType("application/json;charset=utf-8");
                        PrintWriter out = resp.getWriter();
                        Map<String,Object> map = new HashMap<>();
                        map.put("status",403);
                        map.put("message","登录信息失效!");
                        out.write(new ObjectMapper().writeValueAsString(map));
                        out.flush();
                        out.close();
                    }
                });
//                .and()
//                .logout()
//                .permitAll()
//                .and()
//                .rememberMe()
//                .tokenValiditySeconds(1800)
    }

    /**
     * 密码加密器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        /**
         * BCryptPasswordEncoder:相同的密码明文每次生成的密文都不同,安全性更高
         */
//        return new BCryptPasswordEncoder();
        return NoOpPasswordEncoder.getInstance();	//不加密
    }
}
  1. 重写登录函数loadUserByUsername
@Service
public class securityUserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    UsersMapper usersMapper;
    @Autowired
    RolesMapper rolesMapper;

    /**
     * 用户登录认证逻辑:UserDetailsService
     * loadUserByUsername(String username)的参数就是登录时提交的用户名,返回类型是一个叫UserDetails 的接口,
     * 需要在这里构造出他的一个实现类User,这是Spring security提供的用户信息实体。
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DisabledException{

        if (username == null || "".equals(username)) {
            throw new BadCredentialsException("用户不能为空");
        }
		//根据用户名查询用户,注意这里的Users是自定义的user
        Users user = usersMapper.selectOne(new QueryWrapper<Users>().eq("username",username));	//使用mybatis-plus提供的方法查询用户
//        Users user = usersMapper.selectByName(username);

        boolean isEnabled = true;       //是不是激活的
        boolean accountNonExpired = true;       //账户是否过期
        boolean credentialsNonExpired = true;   //认证是否过期
        boolean accountNonLocked = true;        //是否锁定
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        //通过设置用户表的status字段控制账户是否可用
        if (user.getStatus() == 0) {
            isEnabled = false;
        }
        //设置时间
        user.setLastLoginTime(LocalDateTime.now());
        usersMapper.updateById(user);	//更新最近登陆时间
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        //获取该用户所拥有的权限
        String role = rolesMapper.selectOne(new QueryWrapper<Roles>().eq("id", user.getRid())).getRole(); 
        // 声明用户授权
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_" + role);	//加上前缀,在注解控制接口的时候指挥识别ROLE_前缀的权限
        //我这里定义的角色只有一个单一的权限
        grantedAuthorities.add(grantedAuthority);
        //注意这里的User是springsecurity定义的User类
        return new User(user.getUsername(), user.getPassword(), isEnabled, accountNonExpired, credentialsNonExpired, accountNonLocked, grantedAuthorities);
    }
}
  1. 接口权限控制
    接口权限控制
  • tips:spring-security还可以在数据库存储不同角色对应的url路径,通过控制不同路径的权限来实现前端不同角色对应不同的菜单页面。
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值