iT邦幫忙

2021 iThome 鐵人賽

DAY 7
0
自我挑戰組

Angular+Spring Boot API 處理股市資料系列 第 7

JWT實作(三)(Day7)

我們現在設定兩種權限,管理員(ADMIN)&正常(NORMAL)

要實作權限功能,我們先在users表單新增 AUTHORITY欄位,預設如果沒有輸入的話是 NORMAL權限

ALTER TABLE `stockapi`.`users` 
ADD COLUMN `AUTHORITY` VARCHAR(45) NOT NULL DEFAULT 'NORMAL' COMMENT '權限' AFTER `PASSWORD`;

修改User 類別的屬性, 新增authority,再加上無參數的建構子不然BeanRowMapper無法初始化

package com.stockAPI.model;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class User {
	
	private Integer id;
	
	private String account;
	
	private String name;
	
	private String password;
	
	private String authority;

  //需加入無參數的建構子,不然BeanRowMapper無法初始化
	public User(){
	
	}
	
	
	public User(String account,String name,String password,String authority) {
		this.account=account;
		this.name=name;
		this.password=password;
	}

}

修改StockUser的getAuthorities() 方法,之前是預設回傳空陣列

package com.stockAPI.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;


import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class StockUser implements UserDetails {
	
	private static final long serialVersionUID = 1L;
	
	
	private User user;


	public StockUser(User user) {
		this.user=user;
	}
	

	//取得此帳號的權限
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		List<SimpleGrantedAuthority> authority_list = new ArrayList<SimpleGrantedAuthority>();
		authority_list.add(new SimpleGrantedAuthority(user.getAuthority()));
		return authority_list;
	}

	@Override
	public String getPassword() {
		return user.getPassword();
	}

	@Override
	public String getUsername() {
		return user.getAccount();
	}

	//驗證此帳號是否未過期,目前沒有要用到先設return true
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	//驗證此帳號是否未被封鎖,目前沒有要用到先設return true
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	//驗證此帳號憑證是否未過期,目前沒有要用到先設return true
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	//驗證此帳號是否可以使用,目前沒有要用到先設return true
	@Override
	public boolean isEnabled() {
		return true;
	}

}

接著為了與新增會員的權限作區別(只有管理員可以新增會員)

我們實作一個新功能是根據帳號查詢自己資料(大家都可以使用)

在StockUserService新增一個方法是 getOwnData

package com.stockAPI.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.stockAPI.model.StockUser;
import com.stockAPI.model.User;
import com.stockAPI.repository.UserRepository;

@Service
public class StockUserService implements UserDetailsService {
	
	@Autowired
	UserRepository userRepository;
	
	//載入套件的加密器
	@Autowired
	BCryptPasswordEncoder bCryptPasswordEncoder;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User user= userRepository.getDataByAccount(username);
		return new StockUser(user);
		
	}
	
	public Integer addUser(User user) {
		user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
		Integer user_id = userRepository.add(user);
		return user_id;
	}
	
	public StockUser getOwnData(String account){
		User user= userRepository.getDataByAccount(account);
		//資料內不可以含有密碼資訊
		user.setPassword(null);
		return new StockUser(user);
	}
}

在UserController 新增查詢連結

package com.stockAPI.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.stockAPI.model.APIReturnObject;
import com.stockAPI.model.StockUser;
import com.stockAPI.model.User;
import com.stockAPI.service.StockUserService;

@RestController
@RequestMapping("user")
public class UserController {
	
	@Autowired
	StockUserService stockUserService;
	
	@GetMapping("testBlock")
	public String testBlock() {
		return "testBlock";
	}
	
	@GetMapping("testUnblock")
	public String testUnblock() {
		return "testUnblock";
	}
	
	@GetMapping("search/{account}")
	public APIReturnObject search(@PathVariable(name="account") String account) {
		APIReturnObject result = new APIReturnObject();
		Map<String, Object> data = new HashMap<String, Object>();
		StockUser  stockUser = stockUserService.getOwnData(account);
		data.put("userData", stockUser.getUser());
		result.setMessage("用戶資料查詢成功");
		result.setData(data);
		return result;
		
	}
	
	@PostMapping("create")
	public APIReturnObject create(@RequestBody User user) {
		APIReturnObject result = new APIReturnObject();
		Map<String, Object> data = new HashMap<String, Object>();
		Integer user_id = stockUserService.addUser(user);
		data.put("user_id", user_id);
		result.setMessage("用戶資料新增成功");
		result.setData(data);
		return result;
	}

}

再來是我們修改Security的設定,並設定查詢連結是所有人都可以使用的

package com.stockAPI.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import com.stockAPI.service.StockUserService;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	StockUserService stockUserService;
	
	@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	http
    		.authorizeRequests()
    		.antMatchers("/user/testUnblock").permitAll()
    		.antMatchers("/user/create").hasAuthority("ADMIN") //管理員可以新增使用者資料
    		.antMatchers("/user/search/**").permitAll() //大家都可以查詢資料
    		.and()
    		.csrf().disable();
        
    }
    
    //先把加密器注入容器
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

這時候讓我們用postman 測試一下

url:http://localhost:8080/user/search/ken123
method:GET

就可以看到資料出現囉
https://ithelp.ithome.com.tw/upload/images/20210922/20138857TO1AhfL7Tt.png

然後再試著執行我們之前創建使用者的請求,就會發現因為設定權限所以我們已經不能請求成功了喔
https://ithelp.ithome.com.tw/upload/images/20210922/20138857g0VoBt0wbI.png

咦! 那我們要怎麼讓系統去辨認我們的權限呢?
這就與我們明天要實作的登入功能有關囉~!!


上一篇
JWT實作(二)(Day6)
下一篇
JWT實作(四)(Day8)
系列文
Angular+Spring Boot API 處理股市資料30

尚未有邦友留言

立即登入留言