springboot結(jié)合oauth2實現(xiàn)權(quán)限認證

1.什么是JWT

Json web token (JWT), 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標準((RFC 7519).該token被設(shè)計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認證的用戶身份信息寒砖,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息,該token也可直接被用于認證著蟹,也可被加密歇盼。

2.優(yōu)點

體積小违寿、傳輸快

支持跨域授權(quán),因為跨域無法共享cookie

分布式系統(tǒng)中扫倡,很好地解決了單點登錄問題

3.使用場景

1. 認證庙洼,這是比較常見的使用場景,只要用戶登錄過一次系統(tǒng)镊辕,之后的請求都會包含簽名出來的token油够,通過token也可以用來實現(xiàn)單點登錄。

2. 交換信息征懈,通過使用密鑰對來安全的傳送信息石咬,可以知道發(fā)送者是誰、放置消息被篡改卖哎。

4.項目克隆地址(以下過程代碼簡寫鬼悠,可自行克隆代碼查看實現(xiàn)過程,這個框架是我自己搭建的亏娜,里邊已經(jīng)集成了很多東西焕窝,喜歡的可以研究研究,都是比較常用的技術(shù)维贺,有什么問題也可以評論它掂,看到會回復(fù),賬號密碼 admin? ?admin)

ssh://admin@121.36.107.248:29418/goudan.git

5.集成過程

(1)導入sql表,我把sql文件放在下圖所示位置

sql文件

(2)添加依賴

依賴

(3)主體有5個文件需要添加虐秋,分別是shiroConfig榕茧、OAuth2Filer配置、OAuth2Realm客给、OAuth2Token用押、TokenGenerator

3.1?shiroConfig

shiroConfig

具體代碼如下

/**

* @program: xiaowu

* @description: Shiro配置

* @author: Wu

* @create: 2020-08-29 09:46

**/

@Configuration

public class ShiroConfig {

@Bean("sessionManager")

public SessionManagersessionManager(){

DefaultWebSessionManager sessionManager =new DefaultWebSessionManager();

? ? ? ? sessionManager.setSessionValidationSchedulerEnabled(true);

? ? ? ? sessionManager.setSessionIdCookieEnabled(true);

? ? ? ? return sessionManager;

? ? }

@Bean("securityManager")

public SecurityManagersecurityManager(OAuth2Realm oAuth2Realm, SessionManager sessionManager) {

DefaultWebSecurityManager securityManager =new DefaultWebSecurityManager();

? ? ? ? securityManager.setRealm(oAuth2Realm);

? ? ? ? securityManager.setSessionManager(sessionManager);

? ? ? ? return securityManager;

? ? }

@Bean("shiroFilter")

public ShiroFilterFactoryBeanshirFilter(SecurityManager securityManager) {

ShiroFilterFactoryBean shiroFilter =new ShiroFilterFactoryBean();

? ? ? ? shiroFilter.setSecurityManager(securityManager);

? ? ? ? //oauth過濾

? ? ? ? Map filters =new HashMap<>();

? ? ? ? filters.put("oauth2", new OAuth2Filter());

? ? ? ? shiroFilter.setFilters(filters);

? ? ? ? Map filterMap =new LinkedHashMap<>();

? ? ? ? filterMap.put("/druid/**", "anon");

? ? ? ? filterMap.put("/app/**", "anon");

? ? ? ? filterMap.put("/login", "anon");

? ? ? ? filterMap.put("/**", "oauth2");

? ? ? ? shiroFilter.setFilterChainDefinitionMap(filterMap);

? ? ? ? return shiroFilter;

? ? }

@Bean("lifecycleBeanPostProcessor")

public LifecycleBeanPostProcessorlifecycleBeanPostProcessor() {

return new LifecycleBeanPostProcessor();

? ? }

@Bean

? ? public DefaultAdvisorAutoProxyCreatordefaultAdvisorAutoProxyCreator() {

DefaultAdvisorAutoProxyCreator proxyCreator =new DefaultAdvisorAutoProxyCreator();

? ? ? ? proxyCreator.setProxyTargetClass(true);

? ? ? ? return proxyCreator;

? ? }

@Bean

? ? public AuthorizationAttributeSourceAdvisorauthorizationAttributeSourceAdvisor(SecurityManager securityManager) {

AuthorizationAttributeSourceAdvisor advisor =new AuthorizationAttributeSourceAdvisor();

? ? ? ? advisor.setSecurityManager(securityManager);

? ? ? ? return advisor;

? ? }

}

3.2? OAuth2Filer? 過濾器(oauth2是一種規(guī)范,springcloud有個springsecurity oauth2是實現(xiàn)靶剑,這里用的jwt)

OAuth2Filer

具體代碼如下

/**

* @program: xiaowu

* @description: oauth2過濾器

* @author: Wu

* @create: 2020-08-29 10:09

**/

public class OAuth2Filterextends AuthenticatingFilter {

@Override

? ? protected AuthenticationTokencreateToken(ServletRequest request, ServletResponse response)throws Exception {

//獲取請求token

? ? ? ? String token = getRequestToken((HttpServletRequest) request);

? ? ? ? if(StringUtil.isBlank(token)){

return null;

? ? ? ? }

return new OAuth2Token(token);

? ? }

@Override

? ? protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

if(((HttpServletRequest) request).getMethod().equals(RequestMethod.OPTIONS.name())){

return true;

? ? ? ? }

return false;

? ? }

@Override

? ? protected boolean onAccessDenied(ServletRequest request, ServletResponse response)throws Exception {

//獲取請求token蜻拨,如果token不存在,直接返回401

? ? ? ? HttpServletRequest httpServletRequest = (HttpServletRequest) request;

? ? ? ? String token = getRequestToken((HttpServletRequest) request);

? ? ? ? if(StringUtil.isBlank(token)){

HttpServletResponse httpResponse = (HttpServletResponse) response;

? ? ? ? ? ? httpResponse.setHeader("Access-Control-Allow-Credentials", "true");

? ? ? ? ? ? httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));

? ? ? ? ? ? JSONObject json =new JSONObject();

? ? ? ? ? ? json.put("code", "401");

? ? ? ? ? ? json.put("msg", "invalid token");

? ? ? ? ? ? httpResponse.getWriter().print(json);

return false;

? ? ? ? }

return executeLogin(request, response);

? ? }

@Override

? ? protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {

HttpServletResponse httpResponse = (HttpServletResponse) response;

? ? ? ? HttpServletRequest httpServletRequest = (HttpServletRequest) request;

? ? ? ? httpResponse.setContentType("application/json;charset=utf-8");

? ? ? ? httpResponse.setHeader("Access-Control-Allow-Credentials", "true");

? ? ? ? httpResponse.setHeader("Access-Control-Allow-Origin", httpServletRequest.getHeader("Origin"));

? ? ? ? try {

//處理登錄失敗的異常

? ? ? ? ? ? Throwable throwable = e.getCause() ==null ? e : e.getCause();

? ? ? ? ? ? JSONObject json =new JSONObject();

? ? ? ? ? ? json.put("code", "401");

? ? ? ? ? ? json.put("msg", throwable.getMessage());

? ? ? ? ? ? httpResponse.getWriter().print(json);

? ? ? ? }catch (IOException e1) {

}

return false;

? ? }

/**

? ? * 獲取請求的token

*/

? ? private StringgetRequestToken(HttpServletRequest httpRequest){

//從header中獲取token

? ? ? ? String token = httpRequest.getHeader("token");

? ? ? ? //如果header中不存在token桩引,則從參數(shù)中獲取token

? ? ? ? if(StringUtil.isBlank(token)){

token = httpRequest.getParameter("token");

? ? ? ? }

return token;

? ? }

}

3.3 OAuth2Realm配置(這個里面可以設(shè)置角色缎讼、權(quán)限和認證信息)

OAuth2Realm

具體代碼如下

/**

* @program: xiaowu

* @description: 認證

* @author: Wu

* @create: 2020-08-29 10:18

**/

@Component

public class OAuth2Realmextends AuthorizingRealm {

@Autowired

? ? private ManagerServicemanagerService;

? ? @Override

? ? public boolean supports(AuthenticationToken token) {

return tokeninstanceof OAuth2Token;

? ? }

/**

? ? * 授權(quán)(驗證權(quán)限時調(diào)用, 控制role 和 permissins時使用)

*/

? ? @Override

? ? protected AuthorizationInfodoGetAuthorizationInfo(PrincipalCollection principals) {

ManagerInfo manager = (ManagerInfo)principals.getPrimaryPrincipal();

? ? ? ? Integer managerId = manager.getManagerId();

? ? ? ? SimpleAuthorizationInfo info =new SimpleAuthorizationInfo();

? ? ? ? // 模擬權(quán)限和角色

? ? ? ? Set permsSet =new HashSet<>();

? ? ? ? Set roles =new HashSet<>();

? ? ? ? if (managerId ==1) {

// 超級管理員-權(quán)限

? ? ? ? ? ? permsSet.add("delete");

? ? ? ? ? ? permsSet.add("update");

? ? ? ? ? ? permsSet.add("view");

? ? ? ? ? ? roles.add("admin");

? ? ? ? }else {

// 普通管理員-權(quán)限

? ? ? ? ? ? permsSet.add("view");

? ? ? ? ? ? roles.add("test");

? ? ? ? }

info.setStringPermissions(permsSet);

? ? ? ? info.setRoles(roles);

? ? ? ? return info;

? ? }

/**

? ? * 認證(登錄時調(diào)用)

*/

? ? @Override

? ? protected AuthenticationInfodoGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException {

String accessToken = (String) token.getPrincipal();

? ? ? ? //根據(jù)accessToken,查詢用戶信息

? ? ? ? ManagerToken managerToken =managerService.queryByToken(accessToken);

? ? ? ? //token失效

? ? ? ? SimpleDateFormat sm =new SimpleDateFormat("yyyyMMddHHmmss");

? ? ? ? Date expireTime;

? ? ? ? boolean flag =true;

? ? ? ? try {

expireTime? ? = sm.parse(managerToken.getExpireTime());

? ? ? ? ? ? flag = managerToken ==null || expireTime.getTime() < System.currentTimeMillis();

? ? ? ? }catch (ParseException e) {

e.printStackTrace();

? ? ? ? }

if(flag){

throw new IncorrectCredentialsException("token失效阐污,請重新登錄");

? ? ? ? }

//查詢用戶信息

? ? ? ? ManagerInfo managerInfo =managerService.getManagerInfo(managerToken.managerId);

? ? ? ? //賬號鎖定

? ? ? ? // if(managerInfo.getStatus() == 0){

? ? ? ? //? ? throw new LockedAccountException("賬號已被鎖定,請聯(lián)系管理員");

// }

? ? ? ? SimpleAuthenticationInfo info =new SimpleAuthenticationInfo(managerInfo, accessToken, getName());

? ? ? ? return info;

? ? }

}

3.4?OAuth2Token設(shè)置

OAuth2Token

3.5?TokenGenerator, 生成token

TokenGenerator

具體代碼

/**

* @program: xiaowu

* @description: 生成token

* @author: Wu

* @create: 2020-08-29 10:26

**/

public class TokenGenerator {

public static StringgenerateValue() {

return generateValue(UUID.randomUUID().toString());

? ? }

private static final char[]hexCode ="0123456789abcdef".toCharArray();

? ? public static StringtoHexString(byte[] data) {

if (data ==null) {

return null;

? ? ? ? }

StringBuilder r =new StringBuilder(data.length *2);

? ? ? ? for (byte b : data) {

r.append(hexCode[(b >>4) &0xF]);

? ? ? ? ? ? r.append(hexCode[(b &0xF)]);

? ? ? ? }

return r.toString();

? ? }

public static StringgenerateValue(String param) {

try {

MessageDigest algorithm = MessageDigest.getInstance("MD5");

? ? ? ? ? ? algorithm.reset();

? ? ? ? ? ? algorithm.update(param.getBytes());

? ? ? ? ? ? byte[] messageDigest = algorithm.digest();

? ? ? ? ? ? return toHexString(messageDigest);

? ? ? ? }catch (Exception e) {

throw new RuntimeException("生成Token失敗", e);

? ? ? ? }

}

}

4.測試(這里以登錄接口驗證為例)

登錄接口

實現(xiàn)層代碼

實現(xiàn)層

mapper文件還有這種寫法(頭一次見休涤,以前都是在業(yè)務(wù)代碼里寫的)

xml文件

postman測試

測試

mysql

接口權(quán)限已經(jīng)完成,剩下的就是根據(jù)過期時間的業(yè)務(wù)代碼笛辟,當然這個token加密算法比較簡單功氨,我們可以更換加密算法,這以后再完善

喜歡請關(guān)注 “蛋皮皮” 微信公眾號手幢!更多干貨等你來學習哦捷凄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市围来,隨后出現(xiàn)的幾起案子跺涤,更是在濱河造成了極大的恐慌,老刑警劉巖监透,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桶错,死亡現(xiàn)場離奇詭異,居然都是意外死亡胀蛮,警方通過查閱死者的電腦和手機院刁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粪狼,“玉大人退腥,你說我怎么就攤上這事≡匍” “怎么了狡刘?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長困鸥。 經(jīng)常有香客問我嗅蔬,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任购城,我火速辦了婚禮吕座,結(jié)果婚禮上虐译,老公的妹妹穿的比我還像新娘瘪板。我一直安慰自己,他們只是感情好漆诽,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布侮攀。 她就那樣靜靜地躺著,像睡著了一般厢拭。 火紅的嫁衣襯著肌膚如雪兰英。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天供鸠,我揣著相機與錄音畦贸,去河邊找鬼。 笑死楞捂,一個胖子當著我的面吹牛薄坏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播寨闹,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼胶坠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了繁堡?” 一聲冷哼從身側(cè)響起沈善,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椭蹄,沒想到半個月后闻牡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡绳矩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年罩润,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埋酬。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡哨啃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出写妥,到底是詐尸還是另有隱情拳球,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布珍特,位于F島的核電站祝峻,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜莱找,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一酬姆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奥溺,春花似錦辞色、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至桦卒,卻和暖如春立美,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背方灾。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工建蹄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人裕偿。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓洞慎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親击费。 傳聞我的和親對象是個殘疾皇子拢蛋,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348