springboot集成springsecurity 使用OAUTH2做权限管理的教程

时间:2021-05-19

Spring Security OAuth2

主要配置,注意application.yml最后的配置resource filter顺序配置,不然会能获取token但是访问一直 没有权限

WebSecurityConfigurerAdapter 所在服务器的web配置

AuthorizationServerConfigurerAdapter 认证服务器配置

ResourceServerConfigurerAdapter 资源服务器配置 这两个配置在 OAuth2Config.java

权限有几种模式:“authorization_code”, “client_credentials”, “refresh_token”, “password”, “implicit”,是在请求token时的当grant_type值

启动项目后:通过controller方法上的注解@PreAuthorize, 设置权限角色

//获取token,password模式,个人ccc的权限,http://localhost:8080/oauth/token?username=ccc&password=456&grant_type=password&scope=test&client_id=client_1&client_secret=123456//check tokenhttp://localhost:8080/oauth/check_token?token=02b2d1ac-2f8d-42b6-8e04-c47ed3601249//access_deniedhttp://localhost:8080/add?access_token=792e1bea-78b8-4a36-bfa8-3b72f1759438//没加token,禁止http://127.0.0.1:8080//其他访问需要access_tokenhttp://127.0.0.1:8080?access_token=7357c921-0561-42bd-b02a-2d4a049cf69ehttp://localhost:8080/list?access_token=2a06c35f-0758-48c7-904e-4db5bc7b2b83

项目结构:

Spring Security OAuth2 demo

//Controller.javapackage boottest.auth;import org.springframework.security.access.prepost.PreAuthorize;import org.springframework.security.core.Authentication;import org.springframework.security.core.authority.SimpleGrantedAuthority;import org.springframework.security.core.context.SecurityContextHolder;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RestController;/** * @author zhanghui * @date 2019/4/24 */@RestController@ResponseBodypublic class Controller { @GetMapping(value = {"/",""}) public String defaut(){ return "defaut"; } @GetMapping("/index") public String index(){ return "index"; } // direct request to "/logout" for logout @RequestMapping("/login") public String login(){ return "<form action=\"/login\" method=\"post\">\n" + " <label for=\"username\">Username</label>:\n" + " <input type=\"text\" id=\"username\" name=\"username\" autofocus=\"autofocus\" /> <br />\n" + " <label for=\"password\">Password</label>:\n" + " <input type=\"password\" id=\"password\" name=\"password\" /> <br />\n" + " <input type=\"submit\" value=\"Login\" />\n" + "</form>"; } @GetMapping("/login-error") public String loginerror(){ return "login-error"; } @PreAuthorize("hasAuthority('ROLE_user')") //判断角色// @PreAuthorize("hasRole('user')") //同上,判断角色,会自动加 前缀 ROLE_ @GetMapping("/list") public String list() { //程序内判断role Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_user"))){ System.out.println("user role2"); } return "to list"; } @PreAuthorize("hasAuthority('ROLE_admin')") @GetMapping("/add") public String add() { return "to add"; }}//MyUserDetailsService.javapackage boottest.auth;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.authority.AuthorityUtils;import org.springframework.security.core.userdetails.User;import org.springframework.security.core.userdetails.UserDetails;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.core.userdetails.UsernameNotFoundException;import org.springframework.stereotype.Service;import java.util.List;/** * @author zhanghui * @date 2019/4/24 */@Servicepublic class MyUserDetailsService implements UserDetailsService { /** * 根据用户的角色判断权限 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //模拟数据库 SysUser sysUser; //password need BCrypt ,http://patible with * the standard MIME-base64 encoding. * @param s the string to decode * @param maxolen the maximum number of bytes to decode * @return an array containing the decoded bytes * @throws IllegalArgumentException if maxolen is invalid */ private static byte[] decode_base64(String s, int maxolen) throws IllegalArgumentException { StringBuffer rs = new StringBuffer(); int off = 0, slen = s.length(), olen = 0; byte ret[]; byte c1, c2, c3, c4, o; if (maxolen <= 0) throw new IllegalArgumentException ("Invalid maxolen"); while (off < slen - 1 && olen < maxolen) { c1 = char64(s.charAt(off++)); c2 = char64(s.charAt(off++)); if (c1 == -1 || c2 == -1) break; o = (byte)(c1 << 2); o |= (c2 & 0x30) >> 4; rs.append((char)o); if (++olen >= maxolen || off >= slen) break; c3 = char64(s.charAt(off++)); if (c3 == -1) break; o = (byte)((c2 & 0x0f) << 4); o |= (c3 & 0x3c) >> 2; rs.append((char)o); if (++olen >= maxolen || off >= slen) break; c4 = char64(s.charAt(off++)); o = (byte)((c3 & 0x03) << 6); o |= c4; rs.append((char)o); ++olen; } ret = new byte[olen]; for (off = 0; off < olen; off++) ret[off] = (byte)rs.charAt(off); return ret; } /** * Blowfish encipher a single 64-bit block encoded as * two 32-bit halves * @param lr an array containing the two 32-bit half blocks * @param off the position in the array of the blocks */ private final void encipher(int lr[], int off) { int i, n, l = lr[off], r = lr[off + 1]; l ^= P[0]; for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) { // Feistel substitution on left word n = S[(l >> 24) & 0xff]; n += S[0x100 | ((l >> 16) & 0xff)]; n ^= S[0x200 | ((l >> 8) & 0xff)]; n += S[0x300 | (l & 0xff)]; r ^= n ^ P[++i]; // Feistel substitution on right word n = S[(r >> 24) & 0xff]; n += S[0x100 | ((r >> 16) & 0xff)]; n ^= S[0x200 | ((r >> 8) & 0xff)]; n += S[0x300 | (r & 0xff)]; l ^= n ^ P[++i]; } lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1]; lr[off + 1] = l; } /** * Cycically extract a word of key material * @param data the string to extract the data from * @param offp a "pointer" (as a one-entry array) to the * current offset into data * @return the next word of material from data */ private static int streamtoword(byte data[], int offp[]) { int i; int word = 0; int off = offp[0]; for (i = 0; i < 4; i++) { word = (word << 8) | (data[off] & 0xff); off = (off + 1) % data.length; } offp[0] = off; return word; } /** * Initialise the Blowfish key schedule */ private void init_key() { P = (int[])P_orig.clone(); S = (int[])S_orig.clone(); } /** * Key the Blowfish cipher * @param key an array containing the key */ private void key(byte key[]) { int i; int koffp[] = { 0 }; int lr[] = { 0, 0 }; int plen = P.length, slen = S.length; for (i = 0; i < plen; i++) P[i] = P[i] ^ streamtoword(key, koffp); for (i = 0; i < plen; i += 2) { encipher(lr, 0); P[i] = lr[0]; P[i + 1] = lr[1]; } for (i = 0; i < slen; i += 2) { encipher(lr, 0); S[i] = lr[0]; S[i + 1] = lr[1]; } } /** * Perform the "enhanced key schedule" step described by * Provos and Mazieres in "A Future-Adaptable Password Scheme" * http://www.openbsd.org/papers/bcrypt-paper.ps * @param data salt information * @param key password information */ private void ekskey(byte data[], byte key[]) { int i; int koffp[] = { 0 }, doffp[] = { 0 }; int lr[] = { 0, 0 }; int plen = P.length, slen = S.length; for (i = 0; i < plen; i++) P[i] = P[i] ^ streamtoword(key, koffp); for (i = 0; i < plen; i += 2) { lr[0] ^= streamtoword(data, doffp); lr[1] ^= streamtoword(data, doffp); encipher(lr, 0); P[i] = lr[0]; P[i + 1] = lr[1]; } for (i = 0; i < slen; i += 2) { lr[0] ^= streamtoword(data, doffp); lr[1] ^= streamtoword(data, doffp); encipher(lr, 0); S[i] = lr[0]; S[i + 1] = lr[1]; } } /** * Perform the central password hashing step in the * bcrypt scheme * @param password the password to hash * @param salt the binary salt to hash with the password * @param log_rounds the binary logarithm of the number * of rounds of hashing to apply * @param cdata the plaintext to encrypt * @return an array containing the binary hashed password */ public byte[] crypt_raw(byte password[], byte salt[], int log_rounds, int cdata[]) { int rounds, i, j; int clen = cdata.length; byte ret[]; if (log_rounds < 4 || log_rounds > 30) throw new IllegalArgumentException ("Bad number of rounds"); rounds = 1 << log_rounds; if (salt.length != BCRYPT_SALT_LEN) throw new IllegalArgumentException ("Bad salt length"); init_key(); ekskey(salt, password); for (i = 0; i != rounds; i++) { key(password); key(salt); } for (i = 0; i < 64; i++) { for (j = 0; j < (clen >> 1); j++) encipher(cdata, j << 1); } ret = new byte[clen * 4]; for (i = 0, j = 0; i < clen; i++) { ret[j++] = (byte)((cdata[i] >> 24) & 0xff); ret[j++] = (byte)((cdata[i] >> 16) & 0xff); ret[j++] = (byte)((cdata[i] >> 8) & 0xff); ret[j++] = (byte)(cdata[i] & 0xff); } return ret; } /** * Hash a password using the OpenBSD bcrypt scheme * @param password the password to hash * @param salt the salt to hash with (perhaps generated * using BCrypt.gensalt) * @return the hashed password */ public static String hashpw(String password, String salt) { BCrypt B; String real_salt; byte passwordb[], saltb[], hashed[]; char minor = (char)0; int rounds, off = 0; StringBuffer rs = new StringBuffer(); if (salt.charAt(0) != '$' || salt.charAt(1) != '2') throw new IllegalArgumentException ("Invalid salt version"); if (salt.charAt(2) == '$') off = 3; else { minor = salt.charAt(2); if (minor != 'a' || salt.charAt(3) != '$') throw new IllegalArgumentException ("Invalid salt revision"); off = 4; } // Extract number of rounds if (salt.charAt(off + 2) > '$') throw new IllegalArgumentException ("Missing salt rounds"); rounds = Integer.parseInt(salt.substring(off, off + 2)); real_salt = salt.substring(off + 3, off + 25); try { passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8"); } catch (UnsupportedEncodingException uee) { throw new AssertionError("UTF-8 is not supported"); } saltb = decode_base64(real_salt, BCRYPT_SALT_LEN); B = new BCrypt(); hashed = B.crypt_raw(passwordb, saltb, rounds, (int[])bf_crypt_ciphertext.clone()); rs.append("$2"); if (minor >= 'a') rs.append(minor); rs.append("$"); if (rounds < 10) rs.append("0"); if (rounds > 30) { throw new IllegalArgumentException( "rounds exceeds maximum (30)"); } rs.append(Integer.toString(rounds)); rs.append("$"); rs.append(encode_base64(saltb, saltb.length)); rs.append(encode_base64(hashed, bf_crypt_ciphertext.length * 4 - 1)); return rs.toString(); } /** * Generate a salt for use with the BCrypt.hashpw() method * @param log_rounds the log2 of the number of rounds of * hashing to apply - the work factor therefore increases as * 2**log_rounds. * @param random an instance of SecureRandom to use * @return an encoded salt value */ public static String gensalt(int log_rounds, SecureRandom random) { StringBuffer rs = new StringBuffer(); byte rnd[] = new byte[BCRYPT_SALT_LEN]; random.nextBytes(rnd); rs.append("$2a$"); if (log_rounds < 10) rs.append("0"); if (log_rounds > 30) { throw new IllegalArgumentException( "log_rounds exceeds maximum (30)"); } rs.append(Integer.toString(log_rounds)); rs.append("$"); rs.append(encode_base64(rnd, rnd.length)); return rs.toString(); } /** * Generate a salt for use with the BCrypt.hashpw() method * @param log_rounds the log2 of the number of rounds of * hashing to apply - the work factor therefore increases as * 2**log_rounds. * @return an encoded salt value */ public static String gensalt(int log_rounds) { return gensalt(log_rounds, new SecureRandom()); } /** * Generate a salt for use with the BCrypt.hashpw() method, * selecting a reasonable default for the number of hashing * rounds to apply * @return an encoded salt value */ public static String gensalt() { return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS); } /** * Check that a plaintext password matches a previously hashed * one * @param plaintext the plaintext password to verify * @param hashed the previously-hashed password * @return true if the passwords match, false otherwise */ public static boolean checkpw(String plaintext, String hashed) { byte hashed_bytes[]; byte try_bytes[]; try { String try_pw = hashpw(plaintext, hashed); hashed_bytes = hashed.getBytes("UTF-8"); try_bytes = try_pw.getBytes("UTF-8"); } catch (UnsupportedEncodingException uee) { return false; } if (hashed_bytes.length != try_bytes.length) return false; byte ret = 0; for (int i = 0; i < try_bytes.length; i++) ret |= hashed_bytes[i] ^ try_bytes[i]; return ret == 0; } //BCrypt Example public static void main(String[] args) { String password = "testpassword"; //hash String hashed = BCrypt.hashpw(password, BCrypt.gensalt()); System.out.println(hashed); //check if(BCrypt.checkpw(password, hashed)){ System.out.println("good password"); } }}

以上这篇springboot集成springsecurity 使用OAUTH2做权限管理的教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章