用戶微服務
用戶微服務密碼加密存入數據庫。
密碼加密
準備工作
-
引入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
-
安全配置類
import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /** * 安全配置類 */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/**").permitAll() .anyRequest().authenticated() .and().csrf().disable(); } }
-
配置加密工具類
package com.tensquare.user.config; import org.springframework.context.annotation.Bean; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Component; import util.IdWorker; /** * 存放所有用戶微服務的bean */ @Component public class UserApplicationConfig { @Bean public BCryptPasswordEncoder bcryptPasswordEncoder(){ return new BCryptPasswordEncoder(); } @Bean public IdWorker idWorker(){ return new IdWorker(1, 8); } }
這裏我把
UserApplication
中的IdWorker
的bean也放到這個類中。
管理員密碼加密
-
修改
AdminService#add
的邏輯,對原始密碼進行加密存儲@Autowired private BCryptPasswordEncoder encoder; /** * 增加 * @param admin */ public void add(Admin admin) { String decodePassword = idWorker.nextId()+""; //密碼加密 admin.setPassword(encoder.encode(decodePassword)); adminDao.save(admin); }
管理員登錄驗證
-
AdminController
新增方法/** * 用戶登陸 */ @RequestMapping(value = "/login", method = RequestMethod.POST) public Result login(@RequestBody Map<String, String> loginMap) { Admin admin = adminService.findByLoginnameAndPassword(loginMap.get("loginname"), loginMap.get("password")); if (admin != null) { return new Result(true, StatusCode.OK, "登陸成功"); } return new Result(false, StatusCode.LOGINERROR, "用戶名或密碼錯誤"); }
-
AdminService
新增方法/** * 根據登陸名和密碼查詢 * * @param loginname * @param password * @return */ public Admin findByLoginnameAndPassword(String loginname, String password){ Admin admin = adminDao.findByLoginname(loginname); if( admin!=null && encoder.matches(password,admin.getPassword())) { return admin; } return null; }
-
AdminDao
新增方法Admin findByLoginname(String loginname);
用戶密碼加密
-
修改
UserService#add(User user, String code)
方法,對原始密碼進行加密存儲/** * 增加 * * @param user 用戶 * @param code 用戶填寫的驗證碼 */ public void add(User user, String code) { //判斷驗證碼是否正確 String syscode = (String) redisTemplate.opsForValue().get("smscode_" + user.getMobile()); //提取系統正確的驗證碼 if (syscode == null) { throw new RuntimeException("請點擊獲取短信驗證碼"); } if (!syscode.equals(code)) { throw new RuntimeException("驗證碼輸入不正確"); } user.setId(idWorker.nextId() + ""); user.setFollowcount(0);//關注數 user.setFanscount(0);//粉絲數 user.setOnline(0L);//在線時長 user.setRegdate(new Date());//註冊日期 user.setUpdatedate(new Date());//更新日期 user.setLastdate(new Date());//最後登陸日期 //密碼加密 user.setPassword(encoder.encode(user.getPassword())); userDao.save(user); }
用戶登錄驗證
-
UserController
新增方法/** * 用戶登陸 */ @RequestMapping(value = "/login", method = RequestMethod.POST) public Result login(String mobile, String password) { User user = userService.findByMobileAndPassword(mobile, password); if (user != null) { return new Result(true, StatusCode.OK, "登陸成功"); } return new Result(false, StatusCode.LOGINERROR, "用戶名或密碼錯誤"); }
-
UserService
新增方法/** * 根據手機號和密碼查詢用戶 * * @param mobile * @param password * @return */ public User findByMobileAndPassword(String mobile, String password) { User user = userDao.findByMobile(mobile); if (user != null && encoder.matches(password, user.getPassword())) { return user; } return null; }
-
UserDao
新增方法User findByMobile(String mobile);
鑑權微服務
鑑權微服務創建Module(省略)
準備工作
鑑權工具類
在tensquare_common
中引入JWT
依賴並編寫工具類
-
引入
JWT
依賴<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.6.0</version> </dependency>
-
編寫工具類
package util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.Date; @Data @ConfigurationProperties("jwt.config") public class JwtUtil { private String key ; private long ttl ;// token有效期 /** * 生成JWT * * @param id * @param subject * @return */ public String createJWT(String id, String subject, String roles) { long nowMillis = System.currentTimeMillis(); Date now = new Date(nowMillis); JwtBuilder builder = Jwts.builder().setId(id) .setSubject(subject) .setIssuedAt(now) .signWith(SignatureAlgorithm.HS256, key).claim("roles", roles); if (ttl > 0) { builder.setExpiration( new Date( nowMillis + ttl)); } return builder.compact(); } /** * 解析JWT * @param jwtStr * @return */ public Claims parseJWT(String jwtStr){ return Jwts.parser() .setSigningKey(key) .parseClaimsJws(jwtStr) .getBody(); } }
管理員後臺登陸簽發token
配置Jwt工具類Bean
在UserApplicationConig
中配置Bean
@Bean
public JwtUtil jwtUtil(){
return new JwtUtil();
}
配置JWT常量
在用戶微服務中的application.yml
中配置相關參數
jwt:
config:
key: imxushuai
ttl: 360000
修改AdminController#login方法
/**
* 用戶登陸
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(@RequestBody Map<String, String> loginMap) {
Admin admin = adminService.findByLoginnameAndPassword(loginMap.get("loginname"), loginMap.get("password"));
if (admin != null) {
//生成token
String token = jwtUtil.createJWT(admin.getId(), admin.getLoginname(), "admin");
Map<String, String> map = new HashMap<>();
map.put("token", token);
map.put("name", admin.getLoginname());//登陸名
return new Result(true, StatusCode.OK, "登陸成功", map);
}
return new Result(false, StatusCode.LOGINERROR, "用戶名或密碼錯誤");
}
統一鑑權攔截器
編寫攔截器
package com.tensquare.user.filter;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import util.JwtUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class JwtFilter extends HandlerInterceptorAdapter {
@Autowired
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
final String token = authHeader.substring(7);
Claims claims = jwtUtil.parseJWT(token);
if (claims != null) {
if("admin".equals(claims.get("roles"))){//如果是管理員
request.setAttribute("admin_claims", claims);
}
if("user".equals(claims.get("roles"))){//如果是用戶
request.setAttribute("user_claims", claims);
}
}
}
return true;
}
}
攔截器中只是對
token
進行解析,只要解析成功就放心,具體的操作權限交給具體的業務進行判斷。比如:刪除用戶
使用
admin
的token,在攔截器中會在Request
中添加key
爲admin_claims
的數據,在執行到具體的controller
當中,只需要判斷是否含有admin_claims
的key
即可,含有該key
就執行邏輯,否則就拋出權限不足異常。
配置攔截器
package com.tensquare.user.config;
import com.tensquare.user.filter.JwtFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class ApplicationConfig extends WebMvcConfigurationSupport {
@Autowired
private JwtFilter jwtFilter;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtFilter).
addPathPatterns("/**").
excludePathPatterns("/**/login");
}
}
用戶登錄生成token
修改UserController#login
方法邏輯
@Autowired
private JwtUtil jwtUtil;
/**
* 用戶登陸
*/
@RequestMapping(value = "/login", method = RequestMethod.POST)
public Result login(@RequestBody Map<String, String> loginMap) {
User user = userService.findByMobileAndPassword(loginMap.get("mobile"), loginMap.get("password"));
if (user != null) {
String token = jwtUtil.createJWT(user.getId(),
user.getNickname(), "user");
Map<String, String> map = new HashMap<>();
map.put("token", token);
map.put("name", user.getNickname());//暱稱
map.put("avatar", user.getAvatar());//頭像
return new Result(true, StatusCode.OK, "登陸成功", map);
}
return new Result(false, StatusCode.LOGINERROR, "用戶名或密碼錯誤");
}