第一步:引入springSecurity。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
默認的配置是攔截所有的路徑。
第二步:寫配置類
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* authorizeRequests:所有security全註解配置實現的開端。表示開始說明需要的權限
* 需要的權限分兩部分,第一部分是攔截的路徑,第二部分訪問路徑需要的權限
* antMatchers:表示攔截路徑,permitAll表示任何權限都可以使用,直接放行所有
* anyRequest():任何的請求,authenticated():認證後才能訪問
* .and().csrf().disable():固定寫法,表示使csrf攔截失效
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
}
這個適配器實現了一些空的方法。這段可以作爲模板貼上去的。
-------------------------------------------------------------------01-----------------------------------------02----------------03-----------------------------------
springboot是把web.xml拿掉的。
web.xml是初始化的,現在這個替代了。
---------------------------------------------------------------------------04-----------------------------------------------------------------------
加密的網址:https://www.jianshu.com/p/89c4c476e189
引入加密算法:
第一步:
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
@Bean
public IdWorker idWorkker(){
return new IdWorker(1, 1);
}
@Bean
public BCryptPasswordEncoder encoder(){
return new BCryptPasswordEncoder();
}
}
第二步:注入和使用,對密碼進行加密存入到數據庫。
public void add(Admin admin) {
admin.setId( idWorker.nextId()+"" ); //雪花分佈式ID生成器
admin.setPassword(encoder.encode(admin.getPassword()));//密碼加密
adminDao.save(admin);
}
第三步:測試
---------------------------------------------------------------------------05-----------------------------------------------------------------------
寫登陸:
第一步:
public Admin login(Admin admin) {
//先根據用戶名查詢對象.
Admin admin_login = adminDao.findByLoginname(admin.getLoginname());
//拿數據庫中的密碼和用戶輸入的密碼匹配是否相同
if(admin_login!=null&&encoder.matches(admin.getPassword(),admin_login.getPassword())){
//保證數據庫中的密碼和用戶輸入的密碼是一致的
//登錄成功
return admin_login;
}
//登錄失敗
return null;
}
知識點:
@RequestBody:可以轉爲對象也可以轉爲map。
第二步:寫controller
-----------------------------------------------------------------------------06----------------------------------------------------------------------------
用戶的註冊登陸的改造:
第一步:加密關鍵代碼
/**
* 增加
* @param user
*/
public void add(User user) {
user.setId( idWorker.nextId()+"" );
//密碼加密
user.setPassword(encoder.encode(user.getPassword()));
user.setFollowcount(0);//關注數
user.setFanscount(0);//粉絲數
user.setOnline(0L);//在線時長//
user.setRegdate(new Date());//註冊日期
user.setUpdatedate(new Date());//更新日期
user.setLastdate(new Date());//最後登陸日期
userDao.save(user);
}
第二步:登陸關鍵代碼
public User login(String mobile,String password) {
User user = userDao.findByMobile(mobile);
if(user!=null && encoder.matches(password,user.getPassword())){
return user;
}
return null;
}
---------------------------------------------------------------------------07-----------------------------------------------------------------------
常見的認證機制:
1.每次都帶上用戶名和密碼,無狀態的。
2.CooKie Auth:登陸的信息在瀏覽器存在cookie,服務器存在session中。安卓ios什麼的不方便。手機端現在越來越流行了。
3.OAuth:
4.Token Auth:
服務端是不存的用JWT算法。到時候我解密就可以了。
這個token的生成策略我們用的是JWT。
---------------------------------------------------------------------------08-----------------------------------------------------------------------
token的優點:
---------------------------------------------------------------------------09-----------------------------------------------------------------------
JWT生成tokrn的規則:
頭部,載荷,簽名。
頭部:
載荷:
簽名:對頭部和載荷進行加密。
最後一點JWT是後臺簽發的。三部分組成。
---------------------------------------------------------------------------10-----------------------------------------------------------------------
JJWT:
第一步:導入座標在common模塊注意是在common模塊裏面。
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
第二步:
List<Object> roles=new ArrayList<>();
roles.add("role1");
roles.add("role2");
JwtBuilder jwtBuilder = Jwts.builder()
//用戶的id用戶名
.setId("666") .setSubject("小馬")
.setIssuedAt(new Date())//何時登陸的
.signWith(SignatureAlgorithm.HS256,"wmlw")//頭部信息 後面的是加的鹽
.setExpiration(new Date(new Date().getTime()+60000))
.claim("roles",roles);
System.out.println(jwtBuilder.compact());
這個set是按照這個標準set的:
----------------------------------------------------------------------------------11---------------------------------------------------------------------------------
解析JWT:
public static void main(String[] args) {
//Claims裏面就是key和value
Claims claims = Jwts.parser().setSigningKey("wmlw")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI2NjYiLCJzdWIiOiLlsI_pqawiLCJpYXQiOjE1ODAzNjA5NzksImV4cCI6MTU4MDM2MTAzOSwicm9sZXNBZGQiOlsicm9sZTEiLCJyb2xlMiJdfQ.Lx9C8olEcY29NHSx90Q0aifA1JjwzwyyKpWkadzk2eI")
.getBody();
System.out.println("用戶id"+claims.getId());
System.out.println("用戶名"+claims.getSubject());
System.out.println("登錄時間"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getIssuedAt()));
System.out.println("過期時間"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(claims.getExpiration()));
System.out.println("角色"+claims.get("rolesAdd"));
}
---------------------------------------------------------------------------12-----------------------------------------------------------------------
token的過期時間:
同上。
---------------------------------------------------------------------------13-----------------------------------------------------------------------
添加自定義的鍵值對:
---------------------------------------------------------------------------14-----------------------------------------------------------------------
token工具類:
第一步:拷貝JwtUtils:
注意下這個微服務的配置文件是引用它的微服務的配置文件讀取的。沒毛病。
第二步:
必傳的信息:id,
---------------------------------------------------------------------------15-----------------------------------------------------------------------
admin登陸生成token:
第一步:我們寫加鹽的yml注意在哪個模塊裏面。
第二步:在啓動類加Jwt工具。
第三步:寫代碼
用戶 角色 權限 都是多對多
@PostMapping("/login")
public Result login(@RequestBody Admin admin) {
Admin adminLogin = adminService.login(admin);
if (adminLogin == null) {
return new Result(false, StatusCode.ERROR, "登錄失敗");
}
//是的前後端可以通話的操作。採用JWT操作
//生成令牌
// List<Object> roles = new ArrayList<>();
// roles.add("role1");
// roles.add("role2");
String token = jwtUtil.createJWT(adminLogin.getId(), adminLogin.getLoginname(), "admin");
Map<String, Object> map = new HashMap<>();
map.put("token", token);
map.put("role", "admin");
return new Result(true, StatusCode.OK, "登錄成功", map);
// return new Result(true, StatusCode.OK, "登錄成功", "登陸憑證");
}
測試登陸:
---------------------------------------------------------------------------16-----------------------------------------------------------------------
我們假設一個場景:刪除的功能。我們要把token放在請求頭裏面。
第一步:request是一次請求,拿到request才能拿到請求頭。
測試:
先登陸:
請求:
--------------------------------------------------------------------------17----------18-------------------------------------------------------------
用攔截器寫:
其實也可以用springSecurity。
jdk1.8的好處:
第一步寫攔截器:
攔截器都放行,不管是什麼,在請求的request寫入角色。
第二步:寫配置configuration
相當於配置xml。
-----------------------------------------------------------------------19------20----------------------------------------------------------------
攔截器的驗證測試:
第一步:改造userService
public void deleteById(String id) {
// String header = request.getHeader("Authorization");
// if (header == null || header.equals("")) {
// throw new RuntimeException("權限不足!");
// }
// if (!header.startsWith("Bearer ")) {
// throw new RuntimeException("權限不足");
// }
// //得到token
// String token = header.substring(7);
// try {
// Claims claims = jwtUtil.parseJWT(token);
// String roles = (String) claims.get("roles");
// if (roles == null && !"admin".equals(roles)) {
// throw new RuntimeException("權限不足");
// }
// } catch (Exception e) {
// throw new RuntimeException("權限不足");
// }
String token=(String)request.getAttribute("claims_admin");
if(token==null || "".equals(token)){
throw new RuntimeException("權限不足");
}
userDao.deleteById(id);
}
測試:略。
--------------------------------------------------21---------------------------------------------
問答的token問題。
登陸才能問問題。
第一步:在UserService。
@PostMapping("/login")
public Result login(@RequestBody User user){
user=userService.login(user.getMobile(),user.getPassword());
if(user==null){
return new Result(false,StatusCode.ERROR,"登錄失敗");
}
String token = jwtUtil.createJWT(user.getId(), user.getMobile(), "user");
Map<String,Object> map =new HashMap<>();
map.put("token",token);
map.put("roles","user");
return new Result(true,StatusCode.OK,"登錄成功",map);
// return new Result(true,StatusCode.OK,"登錄成功","登陸成功");
}
第二步:在問答裏面驗證
yml導入配置:
第三步:將過濾器導入
第四步:
/**
* 增加
* @param problem
*/
@RequestMapping(method=RequestMethod.POST)
public Result add(@RequestBody Problem problem ){
String token=(String)request.getAttribute("claims_user");
if(token ==null || "".equals(token)){
return new Result(false,StatusCode.ACCESSERROR,"權限不足");
}
problemService.add(problem);
return new Result(true,StatusCode.OK,"增加成功");
}
--------------------------------------------------22---------------------------------------------