Apache Shiro is a powerful and easy-to-integrate open-source rights framework that enables authentication, authorization, encryption, session management, and more. Authentication and authorization are the core of authority control, simply, "certification" is to prove who you are? The general practice of WEB applications is to submit user names and passwords through forms for authentication purposes. Authorization allows authenticated users to access protected resources. About Shiro a series of features and advantages, many articles have been enumerated, here no longer repeat, this article focuses on how to implement the Shiro in the Web Application authentication code authentication and how to achieve single sign-on.
13 Reviews:
Yang Xiaojin, software engineer, Shenzhen Computing Systems Co., Ltd.
January 31, 2013
Develop and deploy your next application on the IBM Bluemix cloud platform.
Start your free trial now
User Rights model
Before we uncover the Shiro veil, we need to recognize the user rights model. The user rights model mentioned in this paper refers to the data model used to express user information and user's permission information. Can prove "Who are you?" "," How many protected resources can you access? ”。 In order to achieve a more flexible user rights data model, the user information is usually represented by a single entity, and the user rights information is represented by two entities.
- User information with Loginaccount, the simplest user information may contain only the user name LoginName and password password two attributes. The actual application may contain information such as whether the user is disabled, whether the user information expires, and so on.
- User rights information with role and Permission, role and Permission form a many-to-many relationship. Permission can be understood as an operation on a resource, Role can be simply understood as a collection of Permission.
- Many-to-many relationships are formed between user information and Role. Indicates that the same user can have multiple role, and a role can be owned by multiple users.
Figure 1. User Rights model
Back to top of page
Authentication and authorization Shiro authentication and authorization process
- Resources that are protected by Shiro are certified and authorized. Use Shiro to protect URLs see the "Integration with Spring" section.
- A user accesses a URL protected by Shiro, such as http://host/security/action.do.
- Shiro first check whether the user has passed the certification, if not pass the authentication check, then jump to the login page, otherwise authorization check. The certification process requires the use of realm to obtain user and password information, typically we implement the JDBC Realm, where the information required for user authentication is obtained from the database. If the cache is used, the user information is obtained from the cache except for the first time.
- After the certification is accepted Shiro authorization check, authorization check also need to get user rights information through Realm. The user rights information required by Shiro includes Role or Permission, which can be either or both, depending on the configuration of the protected resource. If the user rights information does not contain the Role or Permission required by Shiro, authorization does not pass. The resource corresponding to the protected URL can be accessed only by authorization, otherwise jump to an unauthorized page.
Shiro Realm
In the Shiro certification and authorization process, the reference to Realm. Realm can be understood as a DAO that reads user information, roles, and permissions. Because most WEB applications use relational databases, it is common practice to implement JDBC realm, which later mentions the implementation of CAS realm and another realm.
Listing 1. Implement your own JDBC Realm
public class Myshirorealm extends authorizingrealm{//business interface for obtaining user information and user rights information private Businessmanager Businessmanag Er Get authorization information protected Authorizationinfo Dogetauthorizationinfo (principalcollection principals) {String Usern Ame = (String) Principals.fromrealm (GetName ()). Iterator (). Next (); if (username! = null) {//query user authorization Information collection<string> pers=businessmanager.querypermissions (username) ; if (pers! = null &&!pers.isempty ()) {Simpleauthorizationinfo info = new Simpleauthorizationinfo (); for (String each:pers) info.addstringpermissions (each); return info; }} return null; }//Get authentication information protected AuthenticationInfo dogetauthenticationinfo (Authenticationtoken authctoken) throws Au thenticationexception {Usernamepasswordtoken token = (usernamepasswordtoken) Authctoken; Receive via FormThe user name String username = token.getusername (); if (username! = NULL &&! "". Equals (username)) {Loginaccount account = Businessmanager.get (username); if (account! = null) {return new Simpleauthenticationinfo (Account.getloginname (), ACCOUNT.GETP Assword (), GetName ()); }} return null; } }
Code Description:
- Businessmanager represents a business class that obtains user information and user rights information from a database, and the actual situation may vary depending on the user rights model design or the persistence framework, and no sample code is presented here.
- Dogetauthenticationinfo method, fetch user information. In contrast to the user rights model, the Loginaccount entity is taken. Eventually we need to provide AuthenticationInfo objects for Shiro.
- Dogetauthorizationinfo method to obtain user rights information. The code gives an example of getting the user Permission, similar to the code that gets the user Role. The user rights information provided for Shiro is returned as an Authorizationinfo object.
Back to top of page
Why do you have a passion for Shiro?
Maybe someone has to ask, I have been using spring, the security components of the application have already chosen spring security, why need Shiro? Of course, it is undeniable that Spring security is also an excellent safety control component. The purpose of this article is not to allow you to choose Shiro and to abandon Spring Security in an objective manner, with a slight comparison between the two:
- Simplicity, Shiro is easier to use than Spring Security and easier to understand.
- Flexibility, Shiro can run in any application environment, such as Web, EJB, IoC, Google app Engine, without relying on these environments. Spring Security can only be used with spring integration.
- Pluggable, Shiro clean APIs and design patterns make it easy to integrate with many other frameworks and applications. Shiro can be seamlessly integrated with third-party frameworks such as Spring, Grails, Wicket, Tapestry, Mule, Apache Camel, and Vaadin. Spring Security seems to be catching geumcheon in this respect.
Back to top of page
Integration with Spring
Spring is widely used in Java WEB application development, and it can be said that spring is the mainstream in comparison with EJBS. Shiro itself provides good support for spring, and it's easy to integrate spring into your application.
With the user rights data model mentioned earlier, and the implementation of your Realm, we can begin to integrate Shiro for the application service.
Installation of Shiro
Shiro installation is very simple, in the Shiro official website download Shiro-all-1.2.0.jar, Shiro-cas-1.2.0.jar (Single sign-on needs), and slf4j website download Shiro rely on the log components Slf4j-api-1.6.1.jar. Spring-related JAR packages are not listed here. These JAR packages need to be placed in the Web Engineering/web-inf/lib/directory. At this point, the rest is configured.
Configure filters
First, configuring the filter allows the requested resource to undergo Shiro filtering, similar to the use of other filters.
Listing 2. Web. XML configuration
<filter> <filter-name>shiroFilter</filter-name> <filter-class> Org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> < filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</ Url-pattern> </filter-mapping>
Spring Configuration
Next, just configure a series of beans managed by the Spring container, and the integration is done. The function of each Bean is shown in the code description.
Listing 3. Spring Configuration
<bean id= "Shirofilter" class= "Org.apache.shiro.spring.web.ShiroFilterFactoryBean" > <property name= " SecurityManager "ref=" SecurityManager "/> <property name=" loginurl "value="/login.do "/> <property name=" s Uccessurl "value="/welcome.do "/> <property name=" Unauthorizedurl "value="/403.do "/> <property name=" filt ERs "> <util:map> <entry key=" authc "value-ref=" Formauthenticationfilter "/> </util:m ap> </property> <property name= "filterchaindefinitions" > <value>/=anon /login.do*=authc/logout.do*=anon # Permission Configuration Example/security/account/view.do=authc,perms[secur Ity_account_view]/** = authc </value> </property> </bean> <bean id= "sec Uritymanager "class=" Org.apache.shiro.web.mgt.DefaultWebSecurityManager "> <property name=" Realm "ref=" Myshirorealm "/> </bean> <bean id= "Myshirorealm" class= "Xxx.packagename.MyShiroRealm" > <!--businessmanager to implement user name password query--<propert Y name= "Businessmanager" ref= "Businessmanager"/> <property name= "CacheManager" ref= "ShiroCacheManager"/> & lt;/bean> <bean id= "lifecyclebeanpostprocessor" class= "Org.apache.shiro.spring.LifecycleBeanPostProcessor"/ > <bean id= "Shirocachemanager" class= "Org.apache.shiro.cache.ehcache.EhCacheManager" > <property name= "c Achemanager "ref=" CacheManager "/> </bean> <bean id=" Formauthenticationfilter "class=" Org.apache.shiro.web.filter.authc.FormAuthenticationFilter "/>
Code Description:
- Shirofilter loginurl for the login page address, Successurl for the Login Success page address (if the first access to the protected URL login successful, then jump to the actual access page), Unauthorizedurl authentication failed to access the page (mentioned earlier " Unauthorized pages ").
- The filters property in Shirofilter, Formauthenticationfilter is configured as a filter based on forms authentication.
- Filterchaindefinitions attribute in Shirofilter, anon means anonymous access (no authentication and authorization required), AUTHC means authentication required, Perms[security_account_view] means the user needs to provide a value of " Security_account_view "Permission information. This shows that the connection address is configured as AUTHC or perms[xxx] as a protected resource.
- SecurityManager Realm attribute, configured for our own implementation of realm. For realm, see the "Shiro Realm" section above.
- Myshirorealm is the Realm class we need to implement, and in order to reduce the database pressure, we add a caching mechanism.
- Shirocachemanager is the Shiro configuration of the cache framework EhCache.
Back to top of page
Implement Verification Code authentication
Verification codes are a means of effectively preventing brute force, and the common practice is to generate a string of random strings on the server that are associated with the current user session (which we usually put into session) and then show the end user A picture that has been "disturbed". The next step is allowed only if the user enters the same content as the server produces.
Generate Verification Code
As a demonstration, we chose the Open source verification code component Kaptcha. In this way, we simply configure a Servlet, and the page can display the graphical verification code via the IMG tag.
Listing 4. Web. XML configuration
<!--captcha servlet--> <servlet> <servlet-name>kaptcha</servlet-name> < servlet-class> com.google.code.kaptcha.servlet.KaptchaServlet </servlet-class> </ servlet> <servlet-mapping> <servlet-name>kaptcha</servlet-name> < Url-pattern>/images/kaptcha.jpg</url-pattern> </servlet-mapping>
Extended Usernamepasswordtoken
Shiro form authentication, page submitted user name password and other information, with the Usernamepasswordtoken class to receive, it is easy to think, to receive the page verification code input, we need to expand this class:
Listing 5. Captchausernamepasswordtoken
public class Captchausernamepasswordtoken extends usernamepasswordtoken{ private String captcha; Omit getter and Setter methods public Captchausernamepasswordtoken (String username, char[] password, boolean rememberme, Str ing host,string captcha) { super (username, password, rememberme, host); This.captcha = Captcha; } }
Extended Formauthenticationfilter
Next we extend the Formauthenticationfilter class, overriding the Createtoken method first to obtain the Captchausernamepasswordtoken instance, and then add the validation code to validate the method Docaptchavalidate; Finally, the authentication method covering Shiro is Executelogin, and the verification code is verified before the original form authentication logic processing.
Listing 6. Captchausernamepasswordtoken
public class Captchaformauthenticationfilter extends formauthenticationfilter{public static final String default_capt Cha_param = "Captcha"; Private String Captchaparam = Default_captcha_param; Public String Getcaptchaparam () {return captchaparam; } public void Setcaptchaparam (String captchaparam) {this.captchaparam = Captchaparam; } protected String Getcaptcha (ServletRequest request) {return Webutils.getcleanparam (request, Getcaptchaparam ()); }//Create Token protected Captchausernamepasswordtoken Createtoken (ServletRequest request, Servletresponse R Esponse) {String username = getusername (request); String Password = getpassword (request); String captcha = Getcaptcha (request); Boolean rememberme = Isrememberme (request); String host = gethost (request); return new Captchausernamepasswordtoken (username, password, rememberme, Host,captcha); } //Verification Code Check protected void Docaptchavalidate (HttpServletRequest request, Captchausernamepasswordtoken token) { String captcha = (string) request.getsession (). getattribute (Com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY ); if (Captcha!=null &&!captcha.equalsignorecase (Token.getcaptcha ())) {throw new Incorrectcaptcha Exception ("Captcha Error! "); }}//Authentication protected Boolean Executelogin (ServletRequest request, servletresponse response) throws Except Ion {Captchausernamepasswordtoken token = Createtoken (request, response); try {docaptchavalidate (httpservletrequest) request,token); Subject Subject = getsubject (request, response); Subject.login (token); Return onloginsuccess (token, subject, request, response); } catch (Authenticationexception e) {return onloginfailure (token, E, request, response); } } }
Code Description:
- Add the Captchaparam variable so that the parameter name of the page form submission verification code can be flexibly configured.
- In the Docaptchavalidate method, the Authenticode checksum uses the API provided by the framework Kaptcha.
Add Incorrectcaptchaexception
The previous verification code check does not pass, we throw an exception incorrectcaptchaexception, this class inherits authenticationexception, it is necessary to extend a new exception class, so that the page can be more accurate display error message.
Listing 7. Incorrectcaptchaexception
public class Incorrectcaptchaexception extends authenticationexception{public incorrectcaptchaexception () { super (); } Public incorrectcaptchaexception (String message, throwable cause) { Super (message, cause); } Public incorrectcaptchaexception (String message) { super (message); } Public incorrectcaptchaexception (Throwable cause) { super (cause); } }
The page shows the CAPTCHA error message listing 8. Page Authentication error message display
Object Obj=request.getattribute ( org.apache.shiro.web.filter.authc.FormAuthenticationFilter . Default_error_key_attribute_name); Authenticationexception authexp = (authenticationexception) obj; if (authexp! = null) { String expmsg= ""; if (authexp instanceof unknownaccountexception | | Authexp instanceof incorrectcredentialsexception) { expmsg= "wrong user account or password! "; } else if (authexp instanceof incorrectcaptchaexception) { expmsg= ' captcha Error! "; } else{ expmsg= "Login exception:" +authexp.getmessage (); } Out.print ("<div class=\" error\ ">" +expmsg+ "</div>"); }
Back to top of page
Implement single Sign-on
In the previous chapters, we recognized Shiro's certification and authorization and integrated it with Spring. In reality, there is such a scenario, we have a lot of business systems, according to the previous ideas, if access to each business system, to be certified, so it is a bit difficult to accepting people. Is there a mechanism that allows us to access the target system without having to authenticate once?
The above scenario is the single sign-on SSO that we often mention. Shiro support for CAS starting from version 1.2, CAS is an implementation of single sign-on.
Shiro CAS Certification Process
- The first time a user accesses a protected resource, such as Http://casclient/security/view.do
- The Shiro first caches the request address (http://casclient/security/view.do) because it has not passed the authentication.
- It then jumps to the CAS server for login authentication and needs to be returned to the requesting CAS client upon completion of the CAS service-side authentication, so the return address (called CAS Service in Shiro) must be added to the parameter upon request. such as Http://casserver/login?service=http://casclient/shiro-cas
- After the CAS server is authenticated, the CAS server adds ticket for the return address. such as Http://casclient/shiro-cas?ticket=ST-4-BWMEnXfpxfVD2jrkVaLl-cas
- Next, Shiro verifies that the ticket is valid. Because CAS clients do not provide direct authentication, Shiro will initiate ticket check checks to the CAS server, and only if the server returns success, Shiro will consider the authentication passed.
- Certification passed, enter authorization check. The Shiro authorization check is the same as mentioned earlier.
- The final authorization check passes, the user normally accesses to http://casclient/security/view.do.
CAS Realm
Shiro provides a class named Casrealm, similar to the previously mentioned JDBC Realm, which also includes both authentication and authorization functions. Authentication is the validation of whether the ticket returned from the CAS server is valid, or the authorization to obtain user rights information.
To implement the single sign-on feature, you need to extend the Casrealm class.
Listing 9. Shiro CAS Realm
public class Mycasrealm extends casrealm{ //Get authorization information protected Authorizationinfo dogetauthorizationinfo ( PrincipalCollection principals) { //... Same as previous Myshirorealm } public String Getcasserverurlprefix () { return "Http://casserver/login"; } Public String Getcasservice () { return "Http://casclient/shiro-cas"; } + }
Code Description:
- Dogetauthorizationinfo Obtaining authorization information is the same as in the previous section, "Implementing your own JDBC Realm."
- The authentication function is implemented by the Casrealm provided by Shiro itself.
- The Getcasserverurlprefix method returns the CAS server address, which is typically configured by using parameters.
- The Getcasservice method returns the CAS client processing address, which is typically configured by using parameters.
- The authentication process needs to be keystore, otherwise an exception will occur. Can be specified by setting the system properties, such as System.setproperty ("Javax.net.ssl.trustStore", "keystore-file");
CAS Spring Configuration
The Spring configuration that implements single sign-on is similar to the previous one, and differs from the code description.
Listing 10. Shiro CAS Spring Configuration
<bean id= "Shirofilter" class= "Org.apache.shiro.spring.web.ShiroFilterFactoryBean" > <property name= "Securi Tymanager "ref=" SecurityManager "/> <property name=" loginurl "value=" http://casserver/login?service=http://c Asclient/shiro-cas "/> <property name=" Successurl "value="/welcome.do "/> <property name=" UnauthorizedUrl "Value="/403.do "/> <property name=" Filters "> <util:map> <entry key=" AUTHC "value-ref= "Formauthenticationfilter"/> <entry key= "cas" value-ref= "Casfilter"/> </util:map> </pr operty> <property name= "filterchaindefinitions" > <value>/shiro-cas*=cas/logout . Do*=anon/casticketerror.do*=anon # Permission Configuration Example/security/account/view.do=authc,perms[secu Rity_account_view]/** = authc </value> </property> </bean> <bean id= " SecurityManager "class="Org.apache.shiro.web.mgt.DefaultWebSecurityManager" > <property name= "Realm" ref= "Myshirorealm"/> </ bean> <bean id= "lifecyclebeanpostprocessor" class= "Org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!--CAS Realm--<bean id= "Myshirorealm" class= "Xxx.packagename.MyCasRealm" > <property name= "Cacheman Ager "ref=" Shirocachemanager "/> </bean> <bean id=" Shirocachemanager "class=" Org.apache.shiro.cache.ehcache.EhCacheManager "> <property name=" CacheManager "ref=" CacheManager "/> </ bean> <bean id= "Formauthenticationfilter" class= "Org.apache.shiro.web.filter.authc.FormAuthenticationFilter "/> <!--CAS Filter--<bean id=" Casfilter "class=" Org.apache.shiro.cas.CasFilter "> <property name = "Failureurl" value= "casticketerror.do"/> </bean>
Code Description:
- Shirofilter in the Loginurl property, the service-side address of the login CAS, and the parameter service is the return address of the server.
- Myshirorealm is the CAS Realm mentioned in the previous section.
- The Failureurl property in Casfilter is the error page that is displayed when the Ticket check fails.
Back to top of page
Summarize
At this point, we have a more in-depth understanding of Shiro. Shiro flexible, powerful, almost meet our actual application of all kinds of situations, but also what? Let me start using Shiro to escort the app!
Reference Learning
- Spring's official website for more information about spring.
- Apacheshiro the official website to learn more about Shiro.
- CAS official website, learn cas-related content download the CAS server sample.
- Kaptcha, understand the implementation of the verification code.
- Slf4j,shiro depends on the log component.
- Lightssh: Author in Google Code Open source project, the majority of the source code can be found through the download.
- DeveloperWorks Java Technology Zone: Here are hundreds of articles on various aspects of Java programming.
Discuss
- Join DeveloperWorks Chinese community. View developer-driven blogs, forums, groups, and wikis, and communicate with other DeveloperWorks users.
Applying Apache Shiro in a Web project