前一段时间写了无关登陆的性能。包含 Springboot security 的简略应用,微信扫码登陆,接入 spring cloud 的微信登陆。本文就无关 Springboot security 的登陆做一些简略记录。
我的项目地址见文末
Springboot security 登陆
对于登陆性能的实现采取的是 Basic64
传输登陆信息,token
认证。本文以此为例。
用户登陆就是服务器接管到用户输出的用户名和明码而后与数据库中的用户名和明码比对
。胜利,则颁发X-auth-token
,失败则返回401
而通过 Springboot Security 去实现登陆性能,能够实现登陆与认证的自动化。
实现流程
- 用户在浏览器中输出用户名明码进行登陆,该信息通过 Base64 编码之后放到申请头并发动申请。
- 后盾接管到相干申请之后调用
Basic64
的解码形式进行解码并获取到用户名和明码信息。 - 调用
loadUserByUsername()
办法获取相应用户实体。 - 获取用户实体之后将该用户申请中的明码和实体的明码进行匹配。
- 匹配胜利:颁发 token, 前台进行相干跳转;匹配失败:返回
401
。
注:登录流程的实现由过滤器实现
Springboot security 配置项
通过图示,能够看出咱们须要通知 Springboot security
解码形式(Basic64
), 如何获取用户信息,如何比对明码(PasswordEncoder
), 后续通信如何进行身份认证(X-auth-token
)
其中 ①解码形式,②明码比对形式,③身份认证形式 在我的项目中由配置类设定。④如何获取用户信息 则由实现接口办法实现。
配置文件
在 config
文件夹中创立一个配置类MvcSecurityConfig
,内容如下。
@Configuration
@EnableWebSecurity
@EnableSpringHttpSession
public class MvcSecurityConfig extends WebSecurityConfigurerAdapter {
private final BCryptPasswordEncoder passwordEncoder;
public MvcSecurityConfig() {this.passwordEncoder = new BCryptPasswordEncoder();
User.setPasswordEncoder(this.passwordEncoder);
}
/**
* https://spring.io/guides/gs/securing-web/
*
* @param http http 平安
* @throws Exception 异样
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// 凋谢端口
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/wechat/**").permitAll()
.antMatchers("/websocket/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and().cors()
.and().csrf().disable();
http.headers().frameOptions().disable();}
@Bean
PasswordEncoder passwordEncoder() {return this.passwordEncoder;}
@Bean
public HttpSessionStrategy httpSessionStrategy() {return new HeaderAndParamHttpSessionStrategy();
}
@Bean
public SessionRepository sessionRepository() {return new MapSessionRepository();
}
}
①解码形式 ,②明码比对形式,③身份认证形式 别离对应其中的 httpBasic()
, passwordEncoder()
, httpSessionStrategy()
。
而 ④如何获取用户信息 则在UserService
中实现 UserDetailsService
接口来规定。
①解码形式 即通知后盾前台发送申请时的basic
, 让后盾用basic
解码。
②明码比对形式 定义了如何对传来的明文明码进行加密,加密后的明码才能够存进数据库,同时在配置类的构造方法中对跟用户相干的实体User
的passwordEncoder
进行了设置,在调用 user
实体的 setPassword
办法时会先对明码进行加密之后再设置 password
属性。
public void setPassword(String password) {if (User.passwordEncoder == null) {throw new RuntimeException("未设置 User 实体的 passwordEncoder,请调用 set 办法设置");
}
this.password = User.passwordEncoder.encode(password);
}
③身份认证形式 由自定义类实现接口HttpSessionStrategy
规定认证以 x-auth-token
作为关键字来发放凭证。
④如何获取用户信息 即通过数据库获取,见UserService
中loadUserByUsername()
实现:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = this.userRepository.findByUsername(username).orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
// 设置用户角色
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
return new org.springframework.security.core.userdetails.User(username, user.getPassword(), authorities);
}
这样一个简略的登录过程就实现了,
另外,该实际中设置了 MapSessionRepository
来治理会话,实际上不本人设置也是能够的。
问题
实际上以上这种写法存在一个问题,就是已登录用户在未登记的状况下返回到登录页面而后输出一个谬误的明码,也可能胜利进入零碎。
起因是已登录用户自身有一个能够通过零碎认证的 x-auth-token
,此时用户调用登录接口,后端发现x-auth-token
存在并且能够应用,便对接管到的登录申请放行。而在后端的登录接口并未验证,最终登录胜利。
在 login
办法中增加认证查看能够解决,具体可见代码的 login()
,须要留神的是为了实现手动认证,须要在Spring Security
的配置类中增加如下代码在我的项目中来注入Bean
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();
}
github