如何通过SpringBoot整合SpringSecurity,运用OAUTH2实现权限控制教学?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1628个文字,预计阅读时间需要7分钟。
Spring Security OAuth2 主要配置,注意 application.yml 最末尾的 resource filter 顺序配置,否则可能无法获取 token 但能直接访问,没有权限的 WebSecurityConfigurerAdapter 在服务器的 web 配置中。
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的权限, localhost:8080/oauth/token?username=ccc&password=456&grant_type=password&scope=test&client_id=client_1&client_secret=123456 //check token localhost:8080/oauth/check_token?token=02b2d1ac-2f8d-42b6-8e04-c47ed3601249 //access_denied localhost:8080/add?access_token=792e1bea-78b8-4a36-bfa8-3b72f1759438 //没加token,禁止 127.0.0.1:8080 //其他访问需要access_token 127.0.0.1:8080?access_token=7357c921-0561-42bd-b02a-2d4a049cf69e localhost:8080/list?access_token=2a06c35f-0758-48c7-904e-4db5bc7b2b83
项目结构:
Spring Security OAuth2 demo
//Controller.java package 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 @ResponseBody public 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.java package 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 */ @Service public class MyUserDetailsService implements UserDetailsService { /** * 根据用户的角色判断权限 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //模拟数据库 SysUser sysUser; //password need BCrypt ,www.mindrot.org/projects/jBCrypt/, BCrypt.java if("abc".equals(username)){ sysUser=new SysUser("abc",BCrypt.hashpw("123", BCrypt.gensalt()),"ROLE_admin,ROLE_user"); }else if("ccc".equals(username)){ sysUser=new SysUser("ccc",BCrypt.hashpw("456", BCrypt.gensalt()), "ROLE_user"); }else { sysUser=null; } if (null == sysUser) { throw new UsernameNotFoundException(username); } // authorities 是 roles 集合 List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(sysUser.getRoles()); //上面是根据用户名查出用户信息,下面才会比较传来的password是否正确 return new User(sysUser.getUserName(), sysUser.getPassword(), authorities); } }
//OAuth2Config.java package boottest.auth; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.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做权限管理的教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持易盾网络。
本文共计1628个文字,预计阅读时间需要7分钟。
Spring Security OAuth2 主要配置,注意 application.yml 最末尾的 resource filter 顺序配置,否则可能无法获取 token 但能直接访问,没有权限的 WebSecurityConfigurerAdapter 在服务器的 web 配置中。
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的权限, localhost:8080/oauth/token?username=ccc&password=456&grant_type=password&scope=test&client_id=client_1&client_secret=123456 //check token localhost:8080/oauth/check_token?token=02b2d1ac-2f8d-42b6-8e04-c47ed3601249 //access_denied localhost:8080/add?access_token=792e1bea-78b8-4a36-bfa8-3b72f1759438 //没加token,禁止 127.0.0.1:8080 //其他访问需要access_token 127.0.0.1:8080?access_token=7357c921-0561-42bd-b02a-2d4a049cf69e localhost:8080/list?access_token=2a06c35f-0758-48c7-904e-4db5bc7b2b83
项目结构:
Spring Security OAuth2 demo
//Controller.java package 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 @ResponseBody public 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.java package 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 */ @Service public class MyUserDetailsService implements UserDetailsService { /** * 根据用户的角色判断权限 */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //模拟数据库 SysUser sysUser; //password need BCrypt ,www.mindrot.org/projects/jBCrypt/, BCrypt.java if("abc".equals(username)){ sysUser=new SysUser("abc",BCrypt.hashpw("123", BCrypt.gensalt()),"ROLE_admin,ROLE_user"); }else if("ccc".equals(username)){ sysUser=new SysUser("ccc",BCrypt.hashpw("456", BCrypt.gensalt()), "ROLE_user"); }else { sysUser=null; } if (null == sysUser) { throw new UsernameNotFoundException(username); } // authorities 是 roles 集合 List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(sysUser.getRoles()); //上面是根据用户名查出用户信息,下面才会比较传来的password是否正确 return new User(sysUser.getUserName(), sysUser.getPassword(), authorities); } }
//OAuth2Config.java package boottest.auth; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.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做权限管理的教程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持易盾网络。

