Shiro官方文档翻译——Java Authentication Guide with Apache Shiro
- 2019 年 10 月 30 日
- 筆記
Java Authentication Guide with Apache Shiro
Authentication is the process of identity verification– you are trying to prove a user is who they say they are. To do so, a user needs to provide some sort of proof of identity that your system understands and trust.
The goal of this guide is to walk you through how Authentication in Java is performed in Shiro. If you haven’t already please take moment and go through Shiro’s 10 Minute Tutorial so that you get a basic understanding of how to work with Shiro.
Apache Shiro Java 认证教程 Authentication是一个身份验证过程——你需要证明一个用户就是他们说的那个。所以这样做,一个用户需要提供某种身份证明让你的系统理解并信任。 这个教程的目标是引导你了解在Shiro中,Authentication在java中是如何执行的。如果你还没有查看Shiro’s 10 Minute Tutorial,你需要花几分钟通过这个教程,它会让你对Shiro是如何工作的有个基本的理解。
Terminology you’ll need
- Subject – Security specific user ‘view’ of an application user. It can be a human being, a third-party process, a server connecting to you application application, or even a cron job. Basically, it is anything or anyone communicating with your application.
- Principals – A subjects identifying attributes. First name, last name, social security number, username
- Credentials – secret data that are used to verify identities. Passwords, Biometric data, x509 certificates,
- Realms – Security specific DAO, data access object, software component that talks to a backend data source. If you have usernames and password in LDAP, then you would have an LDAP Realm that would communicate with LDAP. The idea is that you would use a realm per back-end data source and Shiro would know how to coordinate with these realms together to do what you have to do.
你需要记住的术语
- Subject:一个应用程序用户的具体安全性的用户视图。它可能是一个人类,一个第三方流程,一个连接你应用程序的服务程序,甚至是一个定时任务。基本上,它是和你应用程序相连的任何事物或任何人。
- Principals:一个subjects的确认属性。姓、名、身份证号、用户名。
- Credentials:用于认证身份的神秘数据。密码、生物特征数据、x509证书。
- Realms:安全性具体的DAO(数据访问对象),与后端数据源对话的软件组件。如果你在LDAP(轻量级数据访问协议)存在usernames和password,然后你就有一个LDAP Realms,它将会与LDAP通信。这个想法是,你需要一个realm后端端数据源,Shiro会知道如何协调这些Realms在一起,做你必须做的。
How to Authenticate in Java with Shiro
In Shiro’s framework, and most every other framework for that matter, the Java authentication process can be broken up into three distinct steps.
Steps
- Collect the subject’s principals and credentials
- Submit the principals and credentials to an authentication system.
- Allow access, retry authentication, or block access
Here is some code on how you do this in Shiro Specifically.
Shiro在java中是如何认证的 在Shiro框架中,或者针对这个问题的大多数其它框架,Java认证过程可以分成三个不同的步骤。 步骤
- 采集subject的principals和credentials。
- 提交principals和credentials到一个认证系统。
- 允许访问,返回认证,或不允许访问。
这里是在Shiro中你如何执行以上步骤的代码。
Step1 – Collect the subject's principals and credentials
//Example using most common scenario: //String username and password. Acquire in //system-specific manner (HTTP request, GUI, etc) UsernamePasswordToken token = new UsernamePasswordToken( username, password ); //”Remember Me” built-in, just do this: token.setRememberMe(true);
In this particular case, we’re using a class called UsernamePasswordToken. It is the most common authentication token used in the framework.
We use this token to bundle the username and password we acquired in someway in our Java application. Maybe they were submitted via a user web form, an HTTP header, or a command line. In Shiro, it does not matter how you acquire them– it is protocol agnostic.
In this example, we have decided that we want the application to remember users when they return. So once the token is created, we use Shiro’s built-in “Remember-me” feature by setting it to true on the token. This is done using the token’s setRememberMe() method
在这个特别的案例中,我们使用了一个叫
UsernamePasswordToken
的类。在框架中,它是最通用的认证令牌。 我们使用这些令牌去绑定在我们java应用程序中通过某种方式获得的账户名和密码。也许他们是被提交的用户表单,一个http请求头,一个命令行。在Shiro,怎么去获取它不是一个问题——它们与协议无关。 在这个例子中,我们决定当应用程序返回用户信息前记住它们。所以一旦令牌被创建,我们使用Shiro内置的“Remember-me”特征并设置为true。它使用token的setRememberMe()
方法。
Step 2 – Submit the principals and credentials to an authentication system.
So we’ve collected the information in a token and set it to remember returning users. The next step is in the Authentication process is to submit the token to an authentication system. Your authentication system is represented in Shiro by security-specific DAOs, that are referred to as Realms. For more information on realms please check out the Shiro Realm Guide.
In Shiro we try to make this part as quick and easy as humanly possible. We have it down to one line of Java code!
因此,我们采集了令牌信息,并设置它去记住返回的用户。认证过程的下一步是提交令牌去一个认证系统。你的认证系统在Shiro中的代表是安全的具体DAOs,它们被引用称为Realms。更多realms的信息请点击 Shiro Realm Guide。 在Shiro中,我们试图使这部分尽可能的快速和简单。我们已经把它用一行代码完成。
//With most of Shiro, you'll always want to make sure you're working with the currently //executing user, referred to as the subject Subject currentUser = SecurityUtils.getSubject(); //Authenticate the subject by passing //the user name and password token //into the login method currentUser.login(token);
First, we need to acquire the currently executing user, referred to as the subject. A subject is just a security specific view of the user—-it can be a human, a process, cron job, doesn’t matter. In Shiro, there is always a subject instance available to the currently executing thread. The concept of a subject is core to Shiro and most of the framework is centered around working with subjects. In this example, we will name this instance of subject currentUser.
To acquire the subject, we use the SecurityUtils class which is also a core pat of Shiro’s API. It will acquire the currently executing user via the getsubject() method call. And we get back a subject instance that is representing who the current user is who is interacting with the system. At this point in the example, the subject currentUser is anonymous. There is no identity associated with them.
Now with the user representation in hand, we authenticate them by just calling the login()) method and submit the token we just constructed a second ago.
首先,我们需要获得当前存在的用户,把它当做subject引用。一个subject仅仅是一个用户的安全具体视图——它可能是一个人、一个处理、定时任务,都没有问题。在Shiro中,这里总会有一个subject实例可以从当前存在的线程中获得。subject的概念是Shiro的核心,几乎所有的框架都是围绕subject工作的。在这个例子中,我们将这个subject实例命名为
currentUser
。 去获得subject,我们使用SecurityUtils
类,它也是Shiro的API的一个主要成分。它获得当前存在的用户通过调用getsubject()
方法。我们得到返回的一个subject实例,它是与系统交互的当前用户的代表。在例子的这个点,currentUser这个subject是匿名的。它没有与之相关的身份。 现在有关系的代表用户,我们认证它们通过调用login()
方法,并且提交我们一秒前构建的token。
Step 3 – Allow access, retry authentication, or block access
Again really, really easy, single method call. If the login() method call is successful, then the user is logged in and associated with a user account or identity. From here, the user can go about using your application and retain their identity through their session or longer since we have set the “Remember Me” in our example.
But what happens if something fails in the authentication attempt? What if they give you the wrong password or they accessed the system too many times, maybe their account is locked? In this case, Shiro will throw an exception. This is where Shiro’s rich exception hierarchy comes into play.
再次,真的,真的很简单,单方法调用。如果
login()
方法调用成功,借着用户被登录,并包括与用户相关联的账户或身份。从这里,用户可以在应用程序中被使用,和保存它们的身份通过它们的session或者使用不久前学过的我们设置"Remember me"的例子。 但是,如果在验证尝试中,一些东西失败了会发生什么呢?如果他们给你错误的密码或者他们访问系统太长时间了,也许他们账户被锁了会怎么样呢?在这个例子,Shiro将抛出一个异常。这里就是Shiro丰富层次的异常。
try { currentUser.login(token); } catch ( UnknownAccountException uae ) { ... } catch ( IncorrectCredentialsException ice ) { ... } catch ( LockedAccountException lae ) { ... } catch ( ExcessiveAttemptsException eae ) { ... } ... your own ... } catch ( AuthenticationException ae ) { //unexpected error? } //No problems, show authenticated view…
You can take that method call and wrap it in a try/catch block and you can catch all sort of exceptions if you want to handle them and react accordingly. In addition to a rich set of exceptions that Shiro offers, you can create your own if you need custom functionality. For more information, follow this link documentation on AuthenticationException.
你能调用这个方法,等待它进入try/catch模块,你就能捕获所有类型的异常,如果你想要处理它们并做出相应反应。除了Shiro提供的富有的异常设置,你可以创建你自己的自定义功能异常。更多信息,请进入这个文档的链接AuthenticationException。
Security Tip Security best practice is to give generic login failure messages to users because you do not want to aid an attacker trying to break into your system.
安全性小提示 安全性最好的练习是给通用的登录失败提示信息到用户,应为你不想帮助一名黑客尝试打破并进入你的系统。
“Remember Me” Support
As shown in the example above, Shiro supports the notion of “remember me” in adition to the normal login process.
In Shiro, the Subject object supports two methods : isRemembered() and isAuthenticated().
A “remembered” subject has an identity (it is not anonymous) and their identifying attributes,referred to as principals, are remembered from a successful authentication during a previous session.
An authenticated subject has proved their identity during their current session.
"Remember Me"支持 在上面例子所展示的,Shiro在正常的登录过程中支持“remember me”的概念。 在Shiro,subject对象支持两个方法:
isRemembered()
和isAuthenticated()
。 一个“remembered”subject有身份(不是匿名)和它们的确认属性,被引用成principals,在前一个session中,一个成功的认证的subject会被记住。 一个认证subject已经在当前线程中被证实身份。Warning If a subject is remembered, it DOES NOT mean they are authenticated.
警告 如果一个subject被记住,并不代表它被验证.
Remembered vs Authenticated
In shiro it is very important to note that a remembered subject is not an authenticated subject. A check against isAuthenticated() is a much more strict check because authentication is the process of proving you are who you say you are. When a user is only remembered, the remembered identity gives the system an idea who that user probably is, but in reality, has no way of absolutely guaranteeing if the remembered Subject represents the user currently using the application. Once the subject is authenticated, they are no longer considered only remembered because their identity would have been verified during the current session.
So although many parts of the application can still perform user-specific logic based on the remembered principals, such as customized views, it should never perform highly-sensitive operations until the user has legitimately verified their identity by executing a successful authentication attempt.
For example, a check to see if a subject can access financial information should almost always depend on isAuthenticated(), not isRemembered(), to guarantee a verified identity.
Here is a scenario to help illustrate why the the distinction between isAuthenticated and isRemembered is important.
Let’s say you’re using Amazon.com. You log in and you add some books to your shopping cart. A day goes by. Of course your user session has expired and you’ve been logged out. But Amazon “remembers” you, greets you by name, and is still giving you personalized book recommendations. To Amazon, isRemembered() would return TRUE. What happens if you try to use one of the credit cards on file or change your account information? While Amazon “remembers” you, isRemembered() = TRUE, it is not certain that you are in fact you, isAuthenticated()=FALSE. So before you can perform a sensitive action Amazon needs to verify your identity by forcing an authentication process which it does through a login screen. After the login, your identity has been verified and isAuthenticated()=TRUE.
This scenario happens very often over the web so the functionality is built into Shiro helping you easily make the distinction yourself.
Remembered 和 效验 在shiro,有一个非常重要的地方需要记下,一个remembered的subject不是一个authenticated的subject。一个核对
isAuthenticated()
是一个更严格的检查因为authentication是一个证明你是你说的你的过程。当一个用户只是remembered,这个remembered的身份给予系统一个主意,那个用户可能是哪个,但是现实中,没有办法保证缓存的Subject代表的用户是当前应用程序使用的用户。一旦subject验证通过,它会不再考虑仅仅缓存,因为它的身份在当当前线程已经被证实了。 所以通过应用程序的许多部分仍能执行用户具体的逻辑基于缓存的principals,比如定制的视图,它不允许执行高度敏感的操作直到用户拥有合法已证实的身份在它执行一次成功的认证尝试之后。 举个例子,一个查看的检查,如果一个subject能访问财务信息几乎都依赖isAuthenticated()
而不是isRemembered()
,去保证一个已证实的身份。 这里有一个脚本来帮助说明为什么isAuthenticated
和isRemembered
的区别是重要的。 让我们说你正在使用Amazon.com。你登录并且添加了一些书在你的购物车。一天过去了。当然你的用户已过期并且你被注销了。但是亚马逊"remembers"你,问候了你的名字,并且还在给你个性化的书籍推荐。对于亚马逊,isRemembered()
将会返回TRUE
。如果你试图使用一张列表上的信用卡或者修改用户信息会发生什么?当亚马逊"remembered"你,isRemembered() = TRUE
,不确定你其实是你自己,isAuthenticated()=FALSE
。所以之前你能执行一个敏感操作亚马逊需要强迫执行一次认证过程去确认的身份,如使用一个登录页面。登录后,你的身份被验证且isAuthenticated()=TRUE
。 这种场景在web中经常发生,所以这个红石在Shiro中建立是帮助你更容易区分你自己。
Logging Out
Finally, when the user is done using the application, they can log out. And in Shiro, we make logging out quick and easy with a single method call.
注销 最终,当用户完成应用的操作后,它们能注销。在Shiro,我们注销快速又简单,掉一个单独方法。
currentUser.logout(); //removes all identifying information and invalidates their session too.
When you log out in Shiro it will close out the user session and removes any associated identity from the subject instance. If you’re using RememberMe in a web environment, then .logout() will, by default, also delete the RememberMe cookie from the browser.
Lend a hand with documentation
While we hope this documentation helps you with the work you're doing with Apache Shiro, the community is improving and expanding the documentation all the time. If you'd like to help the Shiro project, please consider corrected, expanding, or adding documentation where you see a need. Every little bit of help you provide expands the community and in turn improves Shiro.
The easiest way to contribute your documentation is to submit a pull-request by clicking on the Edit
link below, send it to the User Forum or the User Mailing List.
当你在Shiro中注销它,它会关闭用户session,移除任何相关身份从subject实例中。如果你使用RememberMe在web环境中,当
.logout()
执行,默认情况,也会删除RememberMe的缓存在浏览器上的。 文档帮助 当我们希望文档帮助你工作当你正在使用Apache Shiro,社区总会改善和扩大文档。如果你喜欢帮助Shiro项目,请考虑修正、扩大、或增加文档当你认为需要的。任何一点小的帮助都能提供社区扩大,并提升Shiro。最容易的方式是贡献你的文档,提交一个拉请求通过点击在下面的Edit
链接,发送它到用户论坛或用户邮件列表。