On the usage of Apache Shiro

Source: Internet
Author: User
Tags sha256 algorithm

[Every time I write a blog, is a summary of their own learning, but also hope to help people who meet the same problem]
First of all, why Apache Shiro
Recently learning from the front to the back end to do a website to play, it is necessary to build a website, user and access system is certainly very important. The first is the permission system, you can implement a simple control, you can also use the open source framework. As a learning stage, it is better to refer to the open source framework. After searching online, more than two open source frameworks are now used by Apache Shiro and Spring-security. Spring-security is more powerful, but the configuration is cumbersome, and obviously, the two are contradictory. Shiro configuration is relatively simple, although the function is not so powerful, but also provides a lot of custom-made interfaces. After the comparison between the two, decide or choose Shiro. 2016-05-07 Version 1.0

This is the first stage and only the basic user authentication function is implemented.

First of all, the POM configuration, this will not have to say more.

<span style= "font-family:arial, Helvetica, Sans-serif;" >     <dependency></span>
      <groupId>org.apache.shiro</groupId>      <artifactId>shiro-core</artifactId>      < version>1.2.2</version>    </dependency>    <dependency>      <groupId> org.apache.shiro</groupid>      <artifactId>shiro-web</artifactId>      <version>1.2.2 </version>    </dependency>    <dependency>      <groupid>org.apache.shiro</ groupid>      <artifactId>shiro-spring</artifactId>      <version>1.2.2</version>    </dependency>    <dependency>      <groupId>org.apache.shiro</groupId>      <artifactId>shiro-ehcache</artifactId>      <version>1.2.2</version>    </ Dependency>


Next Spring configuration:

<?xml version= "1.0" encoding= "UTF-8"? ><beans xmlns= "Http://www.springframework.org/schema/beans" xmlns:       Xsi= "Http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation= "Http://www.springframework.org/schema/beans             Http://www.springframework.org/schema/beans/spring-beans.xsd "> <bean id=" Lifecylebeanpostprocessor " class= "Org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean id= "Shirodbrealm" class= "Org.rikey.web . Biz.shiro.ShiroDBRealm ">//Configure Shiro Rights Manager for DB database, <span style=" color: #ff0000; "                                             > need to implement </span&gt, <property name= "Credentialsmatcher" >                            Configure the password checker <bean class= "Org.apache.shiro.authc.credential.HashedCredentialsMatcher" > <property name= "Hashalgorithmname" value= "SHA-256"/> <property Name= "storedcredentialshexencoded" value= "FALSE "/> </bean> </property> </bean> <bean id=" Cacheman Ager "class=" Org.apache.shiro.cache.MemoryConstrainedCacheManager "/> <bean id=" SecurityManager "cl ass= "Org.apache.shiro.web.mgt.DefaultWebSecurityManager" >//Security Manager <property Name= "R       Ealm "ref=" Shirodbrealm "/> <property name=" CacheManager "ref=" CacheManager "/> </bean>               <bean id= "Shirofilter" class= "Org.apache.shiro.spring.web.ShiroFilterFactoryBean" >//permission filters, many of them are known. <property name= "SecurityManager" ref= "SecurityManager"/> <property name= "Loginurl" Val Ue= "/login.htm"/> <property name= "Unauthorizedurl" value= "/403.htm"/> <property name                               = "Filterchaindefinitions" > <value>/login*=anon Anon Anonymous,AUTHC needs authentication/dologin*=anon/register.htm=anon                            /doregister=anon/logout*=anon/css/**=anon /js/**=anon/user/**=anon/**=authc </ value> </property> </bean> <bean class= "Org.springframework.aop.framework.autop Roxy. Defaultadvisorautoproxycreator "/>//These two match on the line <bean class=" org.apache.shiro.spring.security. Interceptor.       Authorizationattributesourceadvisor "> <property name=" SecurityManager "ref=" SecurityManager "/> </bean></beans>

Step three, Web. XML, which also needs to be configured

<filter>        <filter-name>shiroFilter</filter-name>        <filter-class> org.springframework.web.filter.delegatingfilterproxy</filter-class>        <init-param>            < param-name>targetfilterlifecyle</param-name>            <param-value>true</param-value>        < /init-param>    </filter>    <filter-mapping>        <filter-name>shirofilter</ filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>
Configure the filter for Shiro, filtering all URIs


Fourth step: Next, you need to encode it.

1. Note that a shirodbrealm is used earlier, and this is a database-based authentication authorization class that we implement ourselves according to the Shiro interface.

2. In addition, Shiro only provides authentication authorization, for user registration, the password preservation mechanism must be the same as the password encryption mechanism used in Shirodbrealm. (Of course, you can save the plaintext, you do not need to specifically handle the user registration password)

1. Shirodbrealm

Package Org.rikey.web.biz.shiro;import Org.apache.shiro.securityutils;import Org.apache.shiro.authc.*;import Org.apache.shiro.authz.authorizationinfo;import Org.apache.shiro.authz.simpleauthorizationinfo;import Org.apache.shiro.realm.authorizingrealm;import Org.apache.shiro.session.session;import Org.apache.shiro.subject.principalcollection;import Org.apache.shiro.subject.subject;import Org.apache.shiro.util.bytesource;import Org.rikey.web.biz.shiro.result.userloginresult;import Org.rikey.web.dao.userdao;import Org.rikey.web.domain.user;import Javax.annotation.resource;public Class    Shirodbrealm extends Authorizingrealm {@Resource (name = "Userdao") private Userdao Userdao;    private static final String Realm_name = "Shirodbrealm";  @Override protected Authorizationinfo Dogetauthorizationinfo (principalcollection principals) {String UserName =        (String) Super.getavailableprincipal (principals); Simpleauthorizationinfo authorizationinfo = new SimpleauthorizationinfO ();        Subject CurrentUser = Securityutils.getsubject ();            if (null! = CurrentUser) {Session session = Currentuser.getsession ();                if (session! = NULL) {Userloginresult user = (Userloginresult) session.getattribute ("CurrentUser");                Authorizationinfo.addstringpermissions (User.getpermissions ());            return authorizationinfo;    }} return null; } @Override protected AuthenticationInfo dogetauthenticationinfo (Authenticationtoken token) throws Authenticationexc        eption {Usernamepasswordtoken Usernamepasswordtoken = (usernamepasswordtoken) token;        String userName = Usernamepasswordtoken.getusername ();        User user = Userdao.queryuser (userName);        if (user = = NULL | | User.getpassword () = = null) {return null; } simpleauthenticationinfo AuthenticationInfo = new Simpleauthenticationinfo (user, User.getpassword (), ByteSource.U Til.bytes (User.getsalt ()), realm_name);    return authenticationinfo; }}
The Dogetauthorizationinfo method does not look first, this is used to obtain authorization information (the user has permission to each URI information), this time has not touched this.

Focus on the Dogetauthencationinfo method, the caller (the method in the Shiro framework to call) will pass in a token, which will contain the user name, what we want to do in this method is based on the framework passed in the user name, to the database to get the user's password, The salt value is then encapsulated into a Simpleauthenticationinfo object, which goes out, and the rest is left to the Hashedcredentialsmather we configured in spring earlier. (actually to here, you can find, Shiro inside a lot of things, we can achieve their own, such as this credentialsmatcher, can implement our own password check logic, can check the number of password errors, etc.).

5th step:

With the basic work in front of you, you can now use Shiro in your Web project for authentication.

In the controller that handles the logon request:

@RequestMapping (value = {"/dologin.htm"}, method = requestmethod.post) public String dologin (String userName, String pa Ssword,boolean remindMe, model model) {Usernamepasswordtoken token = new Usernamepasswordtoken (userName, password)        ; RemindMe = RemindMe = = null?        False:true;        Token.setrememberme (remindMe);        Subject Subject = Securityutils.getsubject ();        String msg;            try {subject.login (token);            if (subject.isauthenticated ()) {return "redirect:/";                } else {Model.addattribute ("msg", "User name or password error");            return "Login"; }} catch (Incorrectcredentialsexception e) {msg = "Login password error.            Password for Account "+ token.getprincipal () +" was incorrect. ";            Model.addattribute ("msg", MSG);        SYSTEM.OUT.PRINTLN (msg);            } catch (Excessiveattemptsexception e) {msg = "Excessive number of login failures";      Model.addattribute ("msg", MSG);      SYSTEM.OUT.PRINTLN (msg); } catch (Lockedaccountexception e) {msg = "account has been locked.            The account for username "+ token.getprincipal () +" was locked. ";            Model.addattribute ("msg", MSG);        SYSTEM.OUT.PRINTLN (msg); } catch (Disabledaccountexception e) {msg = "account number has been disabled.            The account for username "+ token.getprincipal () +" was disabled. ";            Model.addattribute ("msg", MSG);        SYSTEM.OUT.PRINTLN (msg); } catch (Expiredcredentialsexception e) {msg = "account has expired.            The account for username "+ token.getprincipal () +" was expired. ";            Model.addattribute ("msg", MSG);        SYSTEM.OUT.PRINTLN (msg); } catch (Unknownaccountexception e) {msg = "account does not exist.            There is no user with username of "+ token.getprincipal ();            Model.addattribute ("msg", MSG);        SYSTEM.OUT.PRINTLN (msg); } catch (Unauthorizedexception e) {msg = "You did not get the appropriate authorization!"}        "+ e.getmessage ();    Model.addattribute ("msg", MSG);        SYSTEM.OUT.PRINTLN (msg);    } return "Login"; }

First, notice that there is a sentence in the code: Subject Subject = Securityutils.getsubject (); Securityutils is a Shiro tool class that can get a lot of things related to user login information.

Currently obtains a subject, this subject can obtain the current user's login information and so on, here directly calls the subject login to be OK.

Note that the login parameter, is a userpasswordtoken, see no, and we are in front of the Shirodbrealm in the test password used Userpasswordtoken is the same class. In other words, the object that was checked for the password later is passed in from here.


OK, here it seems, it's done.

Nani, no user data in the database yet? This can not play Ah, also can't verify that we write so much code is not OK.


If you're just trying to test

Can be directly in the Shirodbrealm access authentication information that method will be the user name, encrypted password, salt write dead return on the line.

Else

The next step is to implement a controller for a registered user to write the user data to the database.

Package Org.rikey.web.controller;import Org.apache.shiro.crypto.hash.sha256hash;import Org.rikey.web.dao.UserDao; Import Org.rikey.web.domain.user;import Org.springframework.stereotype.controller;import Org.springframework.ui.model;import Org.springframework.web.bind.annotation.requestmapping;import Org.springframework.web.bind.annotation.requestmethod;import Javax.annotation.resource;import java.util.Random;@    Controllerpublic class Register {@Resource (name = "Userdao") private Userdao Userdao;    private static final String CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";    private static final int salt_length = 6; @RequestMapping (value = "/register.htm", method = requestmethod.get) Public String Register () {return "register"    ; } @RequestMapping (value = {"/doregister"}, method = requestmethod.post) public String doregister (user user, Model mo            Del) {try {String password = User.getpassword (); Random random = new Random ();            Random.setseed (System.nanotime ());            StringBuffer sb = new StringBuffer ();                for (int i = 0; i < salt_length; i + +) {int number = Random.nextint (Chars.length ());            Sb.append (Chars.charat (number));            } String Salt = sb.tostring ();            String hashedPasswordBase64 = new Sha256hash (password, salt). ToBase64 ();            User.setpassword (HASHEDPASSWORDBASE64);            User.setsalt (salt);            Userdao.adduser (user);        return "redirect:/login.htm";            } catch (Exception e) {model.addattribute ("errormsg", "Add user Failed");        return "error"; }    }}



OK, note that no Shiro frame structure is used here, only one method of calculating the hash password is used for Shiro. Exactly what method to use is related to the previous password check algorithm, so here you can extract a public class, made into a policy mode, called here.

Look at the previous Shiro Spring configuration, the password check is the sha256 algorithm, so we also use sha256hash here to encrypt. Note that the salt is randomly generated. OK, write this data to the database.
As for the structure of the user table in the database, you don't have to say more? ID, username, password, salt these are required, what other recent logon times, error retries, and so on, you can think of the necessary can be written in.

On the usage of Apache Shiro

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.