编写登录
编写登录业务的实现类 其login方法会返回一个JWTUtils 的token
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private JwtTokenUtil jwtTokenUtil; public User findByUsername(String username) { User user = userMapper.selectByUserName(username); return user; } public RetResult login(String username, String password) throws AuthenticationException { UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password); final Authentication authentication = authenticationManager.authenticate(upToken); SecurityContextHolder.getContext().setAuthentication(authentication); UserDetails userDetails = userDetailsService.loadUserByUsername(username); return new RetResult(RetCode.SUCCESS.getCode(),jwtTokenUtil.generateToken(userDetails)); } }
最后配置Config
@EnableGlobalMethodSecurity(prePostEnabled = true) @EnableWebSecurity public class WebSecurity extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; @Autowired public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder()); } @Bean(name = BeanIds.AUTHENTICATION_MANAGER) @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and().authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers("/auth/**").permitAll() .anyRequest().authenticated() .and().headers().cacheControl(); http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests(); registry.requestMatchers(CorsUtils::isPreFlightRequest).permitAll(); } @Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); final CorsConfiguration cors = new CorsConfiguration(); cors.setAllowCredentials(true); cors.addAllowedOrigin("*"); cors.addAllowedHeader("*"); cors.addAllowedMethod("*"); urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", cors); return new CorsFilter(urlBasedCorsConfigurationSource); } }
运行,返回token
运行,返回结果为token
SpringSecurity JSON登录
这里配置SpringSecurity之JSON登录
这里需要重写UsernamePasswordAnthenticationFilter类,以及配置SpringSecurity
重写UsernamePasswordAnthenticationFilter
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter { @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { //attempt Authentication when Content-Type is json if(request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE) ||request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)){ //use jackson to deserialize json ObjectMapper mapper = new ObjectMapper(); UsernamePasswordAuthenticationToken authRequest = null; try (InputStream is = request.getInputStream()){ AuthenticationBean authenticationBean = mapper.readValue(is,AuthenticationBean.class); authRequest = new UsernamePasswordAuthenticationToken( authenticationBean.getUsername(), authenticationBean.getPassword()); }catch (IOException e) { e.printStackTrace(); authRequest = new UsernamePasswordAuthenticationToken( "", ""); }finally { setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } } //transmit it to UsernamePasswordAuthenticationFilter else { return super.attemptAuthentication(request, response); } } }
配置SecurityConfig
@Override protected void configure(HttpSecurity http) throws Exception { http .cors().and() .antMatcher("/**").authorizeRequests() .antMatchers("/", "/login**").permitAll() .anyRequest().authenticated() //这里必须要写formLogin(),不然原有的UsernamePasswordAuthenticationFilter不会出现,也就无法配置我们重新的UsernamePasswordAuthenticationFilter .and().formLogin().loginPage("/") .and().csrf().disable(); //用重写的Filter替换掉原有的UsernamePasswordAuthenticationFilter http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } //注册自定义的UsernamePasswordAuthenticationFilter @Bean CustomAuthenticationFilter customAuthenticationFilter() throws Exception { CustomAuthenticationFilter filter = new CustomAuthenticationFilter(); filter.setAuthenticationSuccessHandler(new SuccessHandler()); filter.setAuthenticationFailureHandler(new FailureHandler()); filter.setFilterProcessesUrl("/login/self"); //这句很关键,重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己组装AuthenticationManager filter.setAuthenticationManager(authenticationManagerBean()); return filter; }
这样就完成使用json登录SpringSecurity
Spring Security 密码加密方式
需要在Config 类中配置如下内容
/** * 密码加密 */ @Bean public BCryptPasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); }
即,使用此方法,对密码进行加密, 在业务层的时候,使用此加密的方法
@Service @Transactional public class UserServiceImpl implements UserService { @Resource private UserRepository userRepository; @Resource private BCryptPasswordEncoder bCryptPasswordEncoder; //注入bcryct加密 @Override public User add(User user) { user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); //对密码进行加密 User user2 = userRepository.save(user); return user2; } @Override public ResultInfo login(User user) { ResultInfo resultInfo=new ResultInfo(); User user2 = userRepository.findByName(user.getName()); if (user2==null) { resultInfo.setCode("-1"); resultInfo.setMessage("用户名不存在"); return resultInfo; } //判断密码是否正确 if (!bCryptPasswordEncoder.matches(user.getPassword(),user2.getPassword())) { resultInfo.setCode("-1"); resultInfo.setMessage("密码不正确"); return resultInfo; } resultInfo.setMessage("登录成功"); return resultInfo; } }
即,使用BCryptPasswordEncoder 对密码进行加密,保存数据库
使用数据库认证
这里使用数据库认证SpringSecurity
设计数据表
这里设计数据表
着重配置SpringConfig
@Configurable public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; // service 层注入 @Bean PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 参数传入Service,进行验证 auth.userDetailsService(userService); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/admin/**").hasRole("admin") .anyRequest().authenticated() .and() .formLogin() .loginProcessingUrl("/login").permitAll() .and() .csrf().disable(); } }
这里着重配置SpringConfig
小结
着重讲解了RBAC的权限配置,以及简单的使用SpringSecurity,以及使用SpringSecurity + JWT 完成前后端的分离,以及配置json登录,和密码加密方式,