我的日常

登录/注册
您现在的位置:论坛 盖世程序员(我猜到了开头 却没有猜到结局) 盖世程序员 > 10分钟教会你简单的使用Shiro
总共48086条微博

动态微博

查看: 1490|回复: 0

10分钟教会你简单的使用Shiro

[复制链接]
admin    

1244

主题

544

听众

1万

金钱

管理员

  • TA的每日心情

    2021-2-2 11:21
  • 签到天数: 36 天

    [LV.5]常住居民I

    管理员

    跳转到指定楼层
    楼主
    发表于 2015-06-29 20:17:55 |只看该作者 |倒序浏览
    前言6 I2 z% J. Z: U- ]8 J

    8 K$ U+ W, T" w; O1 l, l1 i欢迎来到Apache Shiro 10分钟之旅!
    9 m! p' E5 t* Y: R5 E8 K9 \, k1 x& O# S8 C8 K6 h
    希望通过这个简单、快速的示例,可以让你对应用程序中使用Shiro有个深入的了解。嗯,10分钟你应该可以搞定它。9 a4 G- R- {. D

    / x5 l$ M9 q% @概述/ W& ]1 m3 O  J3 f& L+ h7 ^4 {
    " I5 a  G3 g- P( j) B
    Apache Shiro是什么?
    1 h* D  C$ U) C) ^$ G6 |" p, u7 o2 q6 u. n* c- O! a) z
    Apache Shiro一个功能强大,使用简单的java安全框架,它为开发人员提供一个直观而全面的认证,授权,加密及会话管理的解决方案。* F# V8 f5 h  G$ z3 t6 C1 S

    ) Y# I; {+ }& V3 ?实际上,Shiro的主要功能是管理应用程序中与安全相关的全部,同时尽可能支持多种实现方法。Shiro是建立在完善的接口驱动设计和面向对象原则之上的,支持各种自定义行为。Shiro提供的默认实现,使其能完成与其他安全框架同样的功能,这不也是我们一直努力想要得到的吗!7 m0 z5 Z* p3 d8 G# c# Y0 `

    1 l0 R4 m% k+ E( ~那么Apache Shiro能用来做什么呢?' l6 J# R* v( E

    , l, E0 W- F0 s1 V: V! X很多,很多,嘿嘿。但是不在快速指南中做介绍,如果你想知道,那怎么办呢?去这里找寻你的答案吧。当然如果你还想知道我们什么时候,以及为什么要"创造"Shiro,去看看Shrio的历史和使命吧。
    : B! [- i- q% W  Y* v4 G- }
    . g# x' A# K5 ^# zOK,现在让我们动手做点儿什么吧。
    & K0 x+ u) z, J3 v  [7 u; `/ `+ ^/ k% q
    注:Shiro可以在任何环境下运行,小到最简单的命令行应用,大到大型的企业应用以及集群应用。但是我们准备在快速指南中使用最最简单的main方法的方式,让你对Shiro的API有个感官的认识。
    6 _/ H' \# [( {- O8 m! j
    6 x9 e# N% A) @: x0 E: Q下载
    4 v" \/ F0 m( h4 J, p! J9 A+ T6 J1 W' `4 c8 [
    确保已经安装了JDK1.5+和Maven2.2+
    " P2 [! E4 E: L7 ]: F去这里下载最新已发布的源码。例子中我们使用1.1.0发布版本。% Q. M* d% `( V
    解压源代码
    : s9 E. o/ f9 W进入快速指南文件夹6 v, _: ]; C  ]; c
    cd shiro-root-1.1.0/samples/quickstart2 E' Q2 E& Z+ Y0 K
    + x' f! B# O7 y, B; s
    运行快速指南
    - N; p! u/ q5 x* zmvn compile exec:java5 A- p7 A7 e7 d/ i1 k

    # E& }  C0 u4 }$ V* L过程中会输出日志信息,用来告诉你正在进行的是什么,最后退出执行。可以在这里"samples/quickstart/src/main/java/Quickstart.java "找到源码,也可以进行修改,记得修改后运行"mvn compile exec:java "即可。
    6 u0 v7 _$ z5 F# m" M- g' w: ^& D7 H$ l( C% w- s7 n. [" B' a
    Quickstart.java) o" @+ F+ {5 \7 e& j. `- p5 H

    4 [8 {# u: x0 j5 u5 cQuickstart.java中包含刚刚我们提到的所有内容(认证、授权等等),通过这个简单的示例可以让你轻松的熟悉Shiro的API。那么,让我们把Quickstart.java中的代码,一点一点剖析,这样便于理解它们的作用。 几乎所有的环境下,都可以通过这种方式获取当前用户:
    . D+ }- p6 t$ r* m4 U+ I
    2 A5 {2 d, J5 |, `Subject currentUser = SecurityUtils.getSubject();  p! q2 K1 x+ U2 @/ x- N* [. t
    ) k6 r* F6 |$ t# [5 U
    通过SecurityUtils.getSubject(),就可以获取当前Subject。Subject是应用中用户的一个特定安全的缩影,虽然感觉上直接使用User会更贴切,但是实际上它的意义远远超过了User。而且每个应用程序都会有自己的用户以及框架,我们可不想和它们混淆在一起,况且Subject就是安全领域公认的名词。OK,我们继续。
    8 k3 M; R3 ~5 b" X$ X% X6 N! g/ J) ?4 S2 j" J
    在单应用系统中,调用getSubject()会返回一个Subject,它是位于应用程序中特定位置的用户信息;在服务器中运行的情况下(比如web应用),getSubject会返回一个位于当前线程或请求中的用户信息。 现在你已经得到了Subject对象,那么用它可以做什么呢?2 l  g! r4 z  |$ w$ C
    ( O- j. |( w4 I$ a1 l% {5 b
    如果你想得到应用中用户当前Session的其他参数,可以这样获取Session对象:" {( D5 y; z! s# B$ X

    8 ~9 t( K& T" |! {6 b+ qSession session = currentUser.getSession();' |  C" ~2 w$ D1 s' j/ W* d5 m, k

    % k) ]) |9 a9 I/ s  A( f( Y; Qsession.setAttribute( "someKey", "aValue" );
    & ]* G, Z4 O+ o$ O# L0 S
    4 D% \' ~. Q9 t3 w% y5 S1 x6 `4 N这个Session对象是Shiro中特有的对象,它和我们经常使用的HttpSession非常相似,但还提供了额外的东西,其中与HttpSession最大的不同就是Shiro中的Session不依赖HTTP环境(换句话说,可以在非HTTP 容器下运行)。
    ' \8 \" `, s# @9 L, q" O8 e% t
    / {4 d( b' I  k* T6 U, c如果将Shiro部署在web应用程序中,那么这个Session就是基于HttpSession的。但是像QuickStart示例那样,在非web环境下使用,Shiro则默认使用EnterpriseSessionManagment。也就是说,不论在应用中的任何一层使用同样的API,却不需要考虑部署环境,这一优点为应用打开一个全新的世界,因为应用中要获取Session对象再也不用依赖于HttpSession或者EJB的会话Bean。而且任何客户端技术都可以共享session 数据。
    1 `& m' \, |6 r+ K& c! `; k& K  T6 k# a/ Z; q
    现在你可以得到当前Subject和它的Session对象。那么我们如何验证比如角色和权限这些东西呢?4 p" {3 x: s2 Q  @( G2 R

    2 S) S/ X2 h' g- H3 |2 K很简单,可以通过已得到的user对象进行验证。Subject对象代表当前用户,但是,谁才是当前用户呢?他们可是匿名用户啊。也就是说,必须登录才能获取到当前用户。没问题,这样就可以搞定:
    ! K- k/ ?/ N, ^! {% y6 {# A
    / l$ B/ g3 j$ y5 s6 Cif ( !currentUser.isAuthenticated() ) {
    9 a# ~5 e  b8 n
    2 j/ ]! s1 G/ ~. ]: K4 Z//collect user principals and credentials in a gui specific manner. X$ s. Z- n  n5 h) Z! Q
    3 D1 d3 ~( v( j: U
    //such as username/password html form, X509 certificate, OpenID, etc.; ^. a5 M5 \3 M( ^' W

    6 \- p' k$ e% b+ v. @//We'll use the username/password example here since it is the most common.
      F0 ]' s; C6 m; Q, s
    ! |9 f6 m0 C' Z8 c7 d//(do you know what movie this is from? ;)6 P$ f2 Z1 w% D4 W9 X
    2 ]9 N' p0 g5 ?( d0 z  p; E
    UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
    # h3 v" o7 U; X- b/ g3 {- A
    $ M$ ?& i- P* ^8 \! L" c* V# ^/ ^//this is all you have to do to support 'remember me' (no config - built in!):
    . \+ t' U# x3 M# N$ S! o! R8 b) K7 ~2 j6 ^0 U( d4 o* ~' T
    token.setRememberMe(true);
    - N) g* o7 V0 p  a0 c5 Y, P
    ' f! k. q- \3 X8 XcurrentUser.login(token);
    7 H2 p6 t* l' k" d; L
    3 e) g6 d# T; ^}: J* G' j2 g& Q9 d  y2 p8 L  J. L

    : D* x4 I  a% c2 e! l0 R$ r8 [就是这样,太简单了吧!
    8 }8 T1 I, Z5 ]3 k% \% g
    7 c$ v* c2 Q# H1 y0 S那登录失败了怎么处理呢?可以通过捕获各类异常,根据不同类型的异常做出不同的处理:
    5 d, e3 S: J: g4 `7 o' {. B( O4 e9 O$ @* K& E
    try {% c0 n! K2 U! w9 X& O

    9 A, d) H) ~0 a9 B# l! @: NcurrentUser.login( token );, O3 m5 ~% _% Y3 m& c* ?0 f

    . S1 e3 m' |0 d8 e7 N& d//if no exception, that's it, we're done!
    2 }  f2 g% g& v9 s7 |* o% H) t. o( ^0 o$ Q) A1 Q
    } catch ( UnknownAccountException uae ) {
    ' \7 S- k& a0 {6 |# o: N* f0 h* N) q, |
    //username wasn't in the system, show them an error message?( y+ z% [6 Y2 u5 }4 x

    3 ]* o0 F  u% h. B} catch ( IncorrectCredentialsException ice ) {" T6 l" h- |( z$ [

    4 u* r* r: O3 c, R//password didn't match, try again?, x# `7 Q2 N& g  X3 m; _

    7 }) r( v( {0 f5 v/ w, ~} catch ( LockedAccountException lae ) {- l3 |& E: l; @, M% |
    0 j. z+ A$ h4 l4 s7 n3 u
    //account for that username is locked - can't login. Show them a message?
    * ^( Y" E6 A1 K0 J; j% A
    % [& b; H/ L, k}
    * J8 n9 v+ d  ~8 P/ F( D) F' N" |1 j) G. g
    ... more types exceptions to check if you want ...: ]* g* R/ @; w* x( X! ~6 X0 N
    8 v/ A% l0 D$ L+ s1 n
    } catch ( AuthenticationException ae ) {
    ( E6 i0 w* h7 A: n5 d% G0 T( h. }0 L* m: c1 W# n
    //unexpected condition - error?
    : e$ Y. K% M; m! n4 m; ?6 V7 ]) b4 H$ x7 J; I
    }1 G& ~# q* D+ J, T/ I

    " S4 L  S7 o# I可以捕获Shiro提供的各种异常,也可以抛出自定义类异常用于处理Shiro未考虑到的情况。预知详情,可以去了解AuthenticationException JavaDoc。
    ' c0 F: R. |+ w# Y$ D0 Y
    1 M- i2 m! o+ O* E9 p+ a提示:最安全的做法是将登录失败的消息告知用户,你总不会帮助攻击者入侵你的系统吧!
    * m' l$ [8 D, s) J- m4 L6 f) t
    * @. g7 L$ p  {) e8 m2 Y9 wOK,现在已经拥有一个登录用户了,我们还能做点儿什么呢?
    $ {8 b: N0 l4 ?4 }* @6 t
    0 @2 T+ Q( i7 Q4 `' P比方说,他们是谁:
    9 y( q# B) K# n- D  {
    7 ^- H6 a7 E* [6 H//print their identifying principal (in this case, a username):- ]( J6 H7 L/ D* M6 o$ j

    ; x5 U+ v7 J. G+ _log.info( "User [" + currentUser.getPrincipal() + "] logged in successfully." );' i/ q$ T! _. W6 e
    ) |) S7 t6 U' W" I4 q
    也可以判断用户是否拥有特定的角色:' H/ f; N' O9 B5 ^3 u. P
    7 H9 y' B5 V1 B4 r: P
    if ( currentUser.hasRole( "schwartz" ) ) {0 C/ E) F* R8 ]+ i% q* O* u6 o
    # y% w: |. i) H7 L
    log.info("May the Schwartz be with you!" );
    8 x0 R4 _: i# m% L$ V
    5 Y/ J) l0 C- s1 l6 \: o9 z  ]6 l} else {$ i+ y: c8 T' ]* i$ a/ T+ e5 Q: Q

    - }4 [$ p7 O* T2 f9 g8 I  rlog.info( "Hello, mere mortal." );4 X: a7 f; h# [3 U

    ) @; q; z' t, ?: H" @}- s% L- j2 l+ s

    * ]" O! C. r; E+ J  F. F还可以判断用户是否对特定某实体有操作权限:
    8 l6 d1 u4 G6 ^+ d
    & {9 M9 @9 K/ D7 k. fif ( currentUser.isPermitted( "lightsaber:weild" ) ) {. P9 a+ W+ q% Q. `
    ' b; K/ X+ {. L" P* p; `: @
    log.info("You may use a lightsaber ring. Use it wisely.");
    1 @4 Q2 ?* x* I+ f  I( O
    3 Y$ _8 L: X6 s% j7 @; P  L} else {/ g1 I3 O  H* N4 S$ x  @0 I% X

    - I$ R6 [% A7 W# {2 k( Llog.info("Sorry, lightsaber rings are for schwartz masters only.");6 {! Y/ P; ^. t. B' L

    + j& q5 h9 b" [}
    , E& B1 m7 C8 _3 R5 L+ b
    # T% F$ B- H$ p+ O  A: D当然,还可以进行功能强大的实例级别的权限验证。通过它可以判断用户是否有访问特定类型实例的权限:5 n- [+ U9 Z/ z% \$ D# ]

    7 w% c5 O) O, Q) F# h1 m: k" qif ( currentUser.isPermitted( "winnebago:drive:eagle5" ) ) {# w1 p  i) m: `7 R+ B$ M0 X

    ) V3 F! n5 @) [+ w& ylog.info("You are permitted to 'drive' the 'winnebago' with license plate (id) 'eagle5'. " +"Here are the keys - have fun!");
    7 A% ~2 G4 p+ S6 L
    . g) v; {) W# `  S( M. Y} else {" k( Z# S/ O' U# T! i: h

    # ^9 h# P, D3 B+ M  {! I+ plog.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");- f( ^" O/ J4 Y5 r& R2 I

    # ~7 j$ s4 y# S( g/ `}  g6 F' z. m1 c5 C; E4 a2 t

    ; t7 x4 w& h$ ^+ c' g# ~- R2 P. g( M( r小菜一碟,对吧。
    + ]8 o9 A1 \# O+ f1 }* t2 M! v' F7 G' ^3 T, ]
    最后,当用户使用完毕,还可以退出应用。
    : g* W+ Q; R# G% F6 W8 Y3 a) {( X4 G0 a" _; P- m
    currentUser.logout(); //removes all identifying information and invalidates their session too.4 K$ }, j! n8 I2 u- A$ ~
    ' {, ]. J% k) D- t! V3 Z4 M6 D
    这些就是使用Apache Shiro开发应用的核心了,当然,Apache Shiro已将将很多复杂的东西封装在内部了,但是现在它就是这么简单。
    ' d# P; ?$ ]6 s# D4 J" G3 n
    - W: _- `1 h( Z6 ~7 K: F& e4 Q你会有疑问吧,用户登录时,谁负责把用户信息(用户名、密码、角色、权限等)取出来,还有运行时,谁负责安全认证呢?当然由你决定了啊。通过将一个实现了Shiro中的Realm的Reaml配置到Shiro中即可。4 h9 b. S% p# S$ M
    / a+ L2 F( C" G4 \
    至于如何配置很大程度上取决于你的运行时环境,比如在单应用、web应用、基于spring或JEE 容器的应用或者组合模式中使用Shiro,配置都有所不同。如何配置已经超出QuickStart示例的范围,因为它的主要目的是帮助你熟悉Shiro的API和概念。7 A3 X3 A! X; g7 _' b
    , B0 T8 `4 _4 I1 W4 V
    如果想进一步了解Shiro,可以看看Authentication Guide和Authorization Guide。也可以查看其他文档(特别是Reference Manual),这里可以解决你的各种疑问。+ O: V4 K, ^  @; o1 z9 F9 h

    . k: h- G) i2 r& L+ i

    科帮网 1、本主题所有言论和图片纯属会员个人意见,与本社区立场无关
    2、本站所有主题由该帖子作者发表,该帖子作者与科帮网享有帖子相关版权
    3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和科帮网的同意
    4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
    5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
    6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
    7、科帮网管理员和版主有权不事先通知发贴者而删除本文


    JAVA爱好者①群:JAVA爱好者① JAVA爱好者②群:JAVA爱好者② JAVA爱好者③ : JAVA爱好者③

    快速回复
    您需要登录后才可以回帖 登录 | 立即注册

       

    关闭

    站长推荐上一条 /1 下一条

    发布主题 快速回复 返回列表 联系我们 官方QQ群 科帮网手机客户端
    快速回复 返回顶部 返回列表