赞
踩
前提条件
注释:MvcJavaConfig,CheckLoginInterceptor,CheckPermissionInterceptor失效
<!--spring security 组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
添加依赖之后发现验证码被拦截了。。。
@EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private CorsFilter corsFilter; @Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 不需要认证 .antMatchers("/api/login","/api/code","/api/logout") .permitAll() // 所有请求都必须被认证,必须登录后被访问 .anyRequest() .authenticated(); // 不基于session,关闭csrf http.csrf().disable(); }
@Data public class LoginUser implements UserDetails { @Getter private Employee employee; public LoginUser(Employee employee) { this.employee = employee; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } @Override public String getPassword() { return employee.getPassword(); } @Override public String getUsername() { return employee.getName(); } /** * 账户是否未过期,过期无法验证 */ @Override public boolean isAccountNonExpired() { return true; } /** * 指定用户是否解锁,锁定的用户无法进行身份验证 */ @Override public boolean isAccountNonLocked() { return true; } /** * 账户是否未过期,过期无法验证 */ @Override public boolean isCredentialsNonExpired() { return true; } /** * 是否可用 ,禁用的用户不能身份验证 */ @Override public boolean isEnabled() { return true; } }
@Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private IEmployeeService employeeService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Employee employee = employeeService.selectByUserName(username); Assert.notNull(employee,"登录用户:"+username + "不存在"); // 构建UserDetails LoginUser loginUser = new LoginUser(employee); return loginUser; } } // 注释:username是接收浏览器的用户名
@Service public class LoginServerImpl implements ILoginServer { @Autowired private RedisUtils redisUtils; @Autowired private PermissionMapper permissionMapper; @Autowired private EmployeeMapper employeeMapper; @Autowired private AuthenticationManager authenticationManager; @Override public Map<String, String> VerificationCode() { // 获取验证码 Map<String, String> verifyCode = VerifyCodeUtil.generateVerifyCode(); // 存放到Redis中 String key = Constant.VerifyCode + verifyCode.get("uuid"); String value = verifyCode.get("code"); redisUtils.set(key,value,Constant.VERIFY_CODE_EXPIRES); // 封装验证码 verifyCode.remove("code"); return verifyCode; } @Override public Employee login(LoginInfoVo loginInfoVo) { // 1校验参数 Assert.notNull(loginInfoVo,"非法参数"); Assert.hasLength(loginInfoVo.getUsername(),"用户名长度不能为空"); Assert.hasLength(loginInfoVo.getPassword(),"密码长度不能为空"); // 2校验验证码 // 用户传过来的验证码 String userCode = loginInfoVo.getCode(); String UserUuid = loginInfoVo.getUuid(); Assert.notNull(userCode,"验证码不能为空"); // 从Redis中获取验证码code String key = Constant.VerifyCode+UserUuid; String code = redisUtils.get(key); // 校验客户端穿传递过来的验证码 Assert.state(VerifyCodeUtil.verification(userCode,code,true),"验证码不正确"); // // 3登录 // Employee employee = employeeMapper.login(loginInfoVo.getUsername(), loginInfoVo.getPassword()); // // 4校验登录逻辑 // Assert.notNull(employee,"用户名或者密码错误"); // ------springSecurity 认证-------------------------- // try { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginInfoVo.getUsername(), loginInfoVo.getPassword()); Authentication authenticate = authenticationManager.authenticate(token); // 假如认证失败,会抛出异常 // 正常跑下来,代码认证成功 // TODO: // token.getPrincipal() --- > string:admin LoginUser loginUser = (LoginUser)authenticate.getPrincipal(); // loginUser Employee employee = loginUser.getEmployee(); // }catch (Exception e){ // e.printStackTrace(); // } // ------springSecurity 认证-------------------------- // 把用户的信息存储到Redis中 // key 设计 rbac:login_employee:emp_id // value 存储的格式 json字符串 String UserValue = JsonUtils.toJsonString(employee); String UserKey= Constant.LOGIN_EMPLOYEE_EMPID + employee.getId(); redisUtils.set(UserKey,UserValue); // 存储当前用户的权限信息到Redis中 // 通过员工表的id找到查询employee_role 找到 roleId,然后通过roleId去找role_permission到对应的permissionId, // 通过permissionId 查询对应permission表找到对应的权限信息 List<String> selectExpressionByEmpId = permissionMapper.selectExpressionByEmpId(employee.getId()); String PermissionValue = JsonUtils.toJsonString(selectExpressionByEmpId); String PermissionKey = Constant.LOGIN_PERMISSION_EMPID+employee.getId(); redisUtils.set(PermissionKey,PermissionValue); return employee; } @Override public void logout(HttpServletRequest request) { // 从请求头中获取empId String userId = request.getHeader(Constant.LOGOUT_USER_ID); // 参数校验 Assert.notNull(userId,"非法参数"); long employeeId = Long.parseLong(userId); // 清除Redis中的数据 redisUtils.del(Constant.LOGIN_PERMISSION_EMPID+employeeId); // 权限 redisUtils.del(Constant.LOGIN_EMPLOYEE_EMPID+employeeId); // 用户 } }
@EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private CorsFilter corsFilter; @Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 不需要认证 .antMatchers("/api/login","/api/code","/api/logout") .permitAll() // 所有请求都必须被认证,必须登录后被访问 .anyRequest() .authenticated(); // 添加跨域过滤器在认证之前 // 添加JWT filter http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 添加CORS filter http.addFilterBefore(corsFilter,JwtAuthenticationTokenFilter.class); // 不基于session,关闭csrf http.csrf().disable(); } // 身份认证接口 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 写UserDetailsService,告诉SS // 并且要告诉密码器 auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } /** * 解决 无法直接注入 AuthenticationManager * @return * @throws Exception */ @Bean public AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); // 直接从父取 } @Bean public PasswordEncoder passwordEncoder(){ return NoOpPasswordEncoder.getInstance(); } }
现象:此时可以登录,但是有跨域问题和每个请求没有认证问题
@Configuration public class MvcJavaConfigV2 implements WebMvcConfigurer { // 跨域配置 @Bean public CorsFilter corsFilter(){ CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowCredentials(true); // 设置访问源地址 configuration.addAllowedOrigin("*"); // 设置访问同源请求头 configuration.addAllowedHeader("*"); // 设置访问同源请求方法 configuration.addAllowedMethod("*"); // 有效期为1800s configuration.setMaxAge(1800L); // 添加映射路径,拦截一切请求 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**",configuration); // 返回新的CorsFilter return new CorsFilter(source); } }
/** * 这个过滤要添加SS中 * 每个请求都要认证,添加过滤器(JwtAuthenticationTokenFilter.java) */ @Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { @Autowired private RedisUtils redisUtils; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // String userId = request.getHeader(Constant.LOGOUT_USER_ID); String employeeJson = redisUtils.get(Constant.LOGIN_EMPLOYEE_EMPID + userId); if(!StringUtils.isEmpty(employeeJson)){ // holder:袋子 Employee employee=(Employee) JsonUtils.fromJson(employeeJson, Employee.class); LoginUser loginUser=new LoginUser(employee); // 告诉SS,我认证过了 UsernamePasswordAuthenticationToken token= new UsernamePasswordAuthenticationToken(loginUser,loginUser.getPassword(),loginUser.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(token); } filterChain.doFilter(request,response); } }
@EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private CorsFilter corsFilter; @Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 不需要认证 .antMatchers("/api/login","/api/code","/api/logout") .permitAll() // 所有请求都必须被认证,必须登录后被访问 .anyRequest() .authenticated(); // 添加跨域过滤器在认证之前 // 添加JWT filter(每个请求都要认证,添加过滤器(JwtAuthenticationTokenFilter)) http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // 添加CORS filter http.addFilterBefore(corsFilter,JwtAuthenticationTokenFilter.class); // 不基于session,关闭csrf http.csrf().disable(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 写UserDetailsService,告诉SS // 并且要告诉密码器 auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } /** * 解决 无法直接注入 AuthenticationManager * @return * @throws Exception */ @Bean public AuthenticationManager authenticationManager() throws Exception { return super.authenticationManager(); // 直接从父取 } @Bean public PasswordEncoder passwordEncoder(){ return NoOpPasswordEncoder.getInstance(); } }
现象:现在是可以登录,并且可以得到认证…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。