SpringBoot+vue 前后端的分离项目笔记 [二] 用户登录验证
用户登录验证主要涉及Token+Jpa+BCryptPasswordEncoder密码验证。
SpringBoot方面
@Entity(name ="manager")
@Data
public class User extends AbstractEntity {
String username;
String password;
String email;
}
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AbstractEntity {
@Id
@GeneratedValue
@Getter
@Setter
Long id;
@CreatedDate
LocalDateTime createdDate;
@LastModifiedDate
LocalDateTime modifiedDate;
}
创建对应实体类的Jpa操作接口
public interface UserRespority extends Repository<User,Long> {
Optional<User> findById(Long id);
Optional<User> findByUsername(String username);
}
tokan方面参考连接:vue+springboot前后端分离实现token登录验证和状态保存的简单实现方案
修改Token工具包,方便后面提取token中的用户信息
TokenUtil.java
/**
* 签名验证
* @param token
* @return
*/
public static User verify(String token){
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT jwt = verifier.verify(token);
User user = new User();
user.setId(jwt.getClaim("useid").asLong());
user.setUsername(jwt.getClaim("username").asString());
return user;
} catch (Exception e){
return null;
}
}
修改tokan拦截器,提取token中的用户信息到request
TokenInterceptor.java
......
response.setCharacterEncoding("utf-8");
String token = request.getHeader("Authorization");
if(token != null){
User result = TokenUtil.verify(token);
if(result != null){
request.setAttribute("user",result);
return true;
}
}
......
整合过滤请求,跨域,以及后面用到的密码验证的安全配置
具体配置教程参考
/**
* 安全配置类
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
private TokenInterceptor tokenInterceptor;
//构造方法
public WebSecurityConfig(TokenInterceptor token){
this.tokenInterceptor = token;
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*");
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer){
configurer.setTaskExecutor(new ConcurrentTaskExecutor(Executors.newFixedThreadPool(3)));
configurer.setDefaultTimeout(30000);
}
@Override
public void addInterceptors(InterceptorRegistry registry){
List<String> excludePath = new ArrayList<>();
//排除拦截,除了注册登录(此时还没token),其他都拦截
excludePath.add("/user/register"); //注册
excludePath.add("/user/getImgCode"); //获取验证码
excludePath.add("/user/login"); //登录
excludePath.add("/static/**"); //静态资源
excludePath.add("/assets/**"); //静态资源
registry.addInterceptor(tokenInterceptor)
.addPathPatterns("/**")
.excludePathPatterns(excludePath);
WebMvcConfigurer.super.addInterceptors(registry);
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 1允许任何域名使用
corsConfiguration.addAllowedOrigin("*");
// 2允许任何头
corsConfiguration.addAllowedHeader("*");
// 3允许任何方法(post、get等)
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
}
BCryptPasswordEncoder密码验证
使用BCryptPasswordEncoder主要是因为数据库的用户登录密码是另一个laravel项目中加密的,要在SpringBoot中验证登录的话,就需要用到BCryptPasswordEncoder。(如不需要,可略过)
具体配置,参考教程:Spring security中的BCryptPasswordEncoder方法对密码进行加密与密码匹配
修改控制器
增加登录验证以及token验证
@RestController
@SpringBootApplication
@RequestMapping("/user")
public class LoginControll {
@Autowired
private UserRespority userRespority;
//生成验证码
@RequestMapping(value = "/getImgCode")
@ResponseBody
public Map<String, String> getImgCode() {
Map<String, String> result = new HashMap<>();
try {
result = ImgValidateCodeUtil.getImgCodeBaseCode(4);
} catch (Exception e) {
System.out.println(e);
}
return result;
}
@RequestMapping(value = "/login",method = RequestMethod.POST)
@ResponseBody
public String login(@RequestBody Map<String,Object> para) throws JsonProcessingException {
HashMap<String,Object> hs=new HashMap<>();
try {
//获取用户信息
User user = userRespority.findByUsername((String)para.get("username")).get();
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
// System.out.println(user.getId());
if(bCryptPasswordEncoder.matches((String)para.get("password"),user.getPassword())){
String token= TokenUtil.sign(user);
hs.put("code",200);
hs.put("token",token);
}else {
hs.put("code",400);
hs.put("msg","密码错误");
}
}catch (NoSuchElementException e){
hs.put("code",400);
hs.put("msg","用户名不存在");
ObjectMapper objectMapper=new ObjectMapper();
}
ObjectMapper objectMapper=new ObjectMapper();
return objectMapper.writeValueAsString(hs);
}
@RequestMapping(value = "/yztokan")
@ResponseBody
public Map<String, String> yztokan(@RequestAttribute(value = "user") User user){
Map<String, String> result = new HashMap<>();
result.put("user",user.getUsername());
return result;
}
}
vue方面
token配置参考教程: vue+springboot前后端分离实现token登录验证和状态保存的简单实现方案
修改登录方法
/*登录*/
tologin:function () {
// this.$axios.post('user/getImgCode')
let v = this.loginForm;
if (v.inputCode === this.code){
// this.$layer.alert("验证通过!");
this.$axios.post('user/login',{
'username':v.username,
'password':v.password
}).then((response) => {
// console.log(response)
if (response.data.code === 200){
this.userToken = response.data.token;
this.changeLogin({Authorization:this.userToken});
this.$layer.msg("登录成功!");
// console.log(this.userToken)
this.$router.push('/');
}else {
this.getIdentifyingCode();
this.$layer.alert(response.data.msg);
}
}).catch((error) => {
console.log(error)
});
}else {
this.$layer.alert("验证错误");
}
}
}
增加token验证方法
ceshi:function () {
// console.log(localStorage.getItem('Authorization'))
this.$axios.get('user/yztokan')
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error);
});
}
效果图
其他参考教程:
官方:Spring Data JPA
相关代码:github.com/spring-projects/spring-...
vue怎么修改title
vue项目中使用vue-layer弹框插件
本作品采用《CC 协议》,转载必须注明作者和本文链接