使用者登入驗證主要涉及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 協議》,轉載必須註明作者和本文連結