Teach you Shiro integrate springboot, avoid all kinds of pits

Source: Internet
Author: User
Tags getmessage

Recently engaged in the Shiro security framework, found some online blog articles, but one to their own realization of the time encountered a variety of pits, need to look at the source of various data and various tests.
Then this article teaches you how to integrate Shiro into the springboot, and avoid some small pits, this time to achieve the basic landing and role permissions, the subsequent article also explains other functions, such as "teach you Shiro + springboot integration JWT"

Attached Source: Https://github.com/HowieYuan/shiro

Dependency Packages
<dependency>    <groupId>org.apache.shiro</groupId>    <artifactId>shiro-spring</artifactId>    <version>1.3.2</version></dependency>
Database tables

Basics, user table, and Role roles table

Shiro Related class Shiro configuration class
@Configurationpublic class Shiroconfig {@Bean public shirofilterfactorybean shirfilter (SecurityManager Securitymana        GER) {Shirofilterfactorybean Shirofilterfactorybean = new Shirofilterfactorybean ();        SecurityManager Shirofilterfactorybean.setsecuritymanager (SecurityManager) must be set; Setloginurl If you do not set a value, the default is to automatically find the "/login.jsp" page or the "/login" Map Shirofilterfactorybean.setloginurl ("/notlogin") under the Web project root directory        ;        Set the URL of the no-limit jump;        Shirofilterfactorybean.setunauthorizedurl ("/notrole");        Set Interceptor map<string, string> filterchaindefinitionmap = new linkedhashmap<> ();        Visitors, Development Authority Filterchaindefinitionmap.put ("/guest/**", "anon");        User, Need role permission "user" Filterchaindefinitionmap.put ("/user/**", "Roles[user]");        admin, Need role permission "admin" filterchaindefinitionmap.put ("/admin/**", "roles[admin]");        Open Login Interface Filterchaindefinitionmap.put ("/login", "anon"); The rest of the interface is blocked//the main line of code mustPut at the end of all permission settings, otherwise it will cause all URLs to be intercepted filterchaindefinitionmap.put ("/**", "authc");        Shirofilterfactorybean.setfilterchaindefinitionmap (FILTERCHAINDEFINITIONMAP);        System.out.println ("Shiro Interceptor factory class injection success");    return Shirofilterfactorybean; }/** * Inject SecurityManager */@Bean public SecurityManager SecurityManager () {Defaultwebsecuritym        Anager SecurityManager = new Defaultwebsecuritymanager ();        Set Realm.        Securitymanager.setrealm (Customrealm ());    return SecurityManager;     }/** * Custom identity authentication realm; * <p> * must write this class and add @Bean annotations to inject customrealm, * otherwise it will affect dependency injection of other classes in the Customrealm class */@Bean public Cust    Omrealm Customrealm () {return new Customrealm (); }}

Note : The inside of the SecurityManager class should be imported, import org.apache.shiro.mgt.SecurityManager; but if you are copying the code over, it will be imported by default java.lang.SecurityManager here is a little bit of pit, other classes, but also belong to the Shiro package inside the class

The Shirfilter method is mainly set up some important jump URLs, such as non-landing, no right-time jump, and set the various types of URL interception, such as/user Start URL requires user permissions,/admin start URL requires Admin permissions, etc.

Permission Intercept Filter

When you run a Web application, Shiro creates some useful default filter instances and automatically makes them available, and these default filter instances are defined by the Defaultfilter enumeration class, and of course we can customize the filter instance. These will be discussed in a future article.

Filter explain
Anon No parameters, open access, can be understood as anonymous users or visitors
Authc No reference, requires authentication
Logout No parameter, logoff, after execution will jump directly to the shiroFilterFactoryBean.setLoginUrl(); URL of the set
Authcbasic No reference, indicating Httpbasic certification
User No parameter, indicates that the user must exist and does not check when logged in operation
Qs. No parameter, indicates a secure URL request, protocol is HTTPS
Perms[user] Parameters can be written in multiple, indicating that one or some permissions are required to pass, multiple parameters are written perms["user, admin"], when there are multiple parameters must pass each parameter to calculate through
Roles[admin] Parameters can be written in multiple, indicating that one or some of the roles can pass, multiple arguments are written roles["Admin,user"], when there are multiple arguments, each parameter must pass to count through
Rest[user] According to the method requested, equivalent to Perms[user:method], wherein method is Post,get,delete, etc.
PORT[8081] When the requested URL port is not 8081, jump to schemal://servername:8081?querystring where Schmal is protocol http or HTTPS and so on, ServerName is the host,8081 you are visiting is the port Port, QueryString is the URL you visited? The following parameters

Commonly used mainly is the anon,authc,user,roles,perms and so on

Note : Anon, authc, Authcbasic, user is the first set of authentication filters, perms, port, rest, roles, SSL is the second set of authorization filters, to pass the authorization filter, First to complete the login authentication operation (that is, the first to complete the certification to seek authorization) to go to the second set of authorizations (such as access to the URL that requires roles permissions, if not logged, will jump directly to the shiroFilterFactoryBean.setLoginUrl(); URL set)

Custom Realm Class

We first have to inherit the Authorizingrealm class from defining our own realm for our custom identity, permission authentication operations.
Remember to override the two methods of overriding Dogetauthenticationinfo and Dogetauthorizationinfo (two method names are very similar, don't make a mistake)

public class Customrealm extends Authorizingrealm {private Usermapper usermapper;    @Autowired private void Setusermapper (Usermapper usermapper) {this.usermapper = Usermapper;     /** * Get authentication information * Shiro, the end is to get the user, role and permission information in the application through Realm. * * @param authenticationtoken User ID token * @return returns the AuthenticationInfo instance that encapsulates the user information */@Override Prot ected authenticationinfo dogetauthenticationinfo (Authenticationtoken authenticationtoken) throws        authenticationexception {System.out.println ("———— identity authentication Method ————");        Usernamepasswordtoken token = (usernamepasswordtoken) Authenticationtoken;        Gets the user String password = usermapper.getpassword (Token.getusername ()) from the database to the application username password;        if (null = = password) {throw new Accountexception ("Incorrect user name"); } else if (!password.equals (New String ((char[)) token.getcredentials ())) {throw new accountexception ("Incorrect password")        ; } return new SimpleauthenticationinfO (Token.getprincipal (), Password, getName ()); /** * Get authorization information * * @param principalcollection * @return */@Override protected Authorizationi        NFO dogetauthorizationinfo (principalcollection principalcollection) {System.out.println ("———— Authority authentication ————");        String username = (string) securityutils.getsubject (). Getprincipal ();        Simpleauthorizationinfo info = new Simpleauthorizationinfo ();        Get the user role String role = Usermapper.getrole (username);        set<string> set = new hashset<> ();        You need to encapsulate the role into Set as a parameter of Info.setroles () set.add (role);        Sets the user-owned role info.setroles (set);    return info; }}

Rewrite the two methods are to implement identity authentication and authorization authentication, Shiro has a method of landing operations Subject.login() , when we encapsulate the user name, password token as a parameter passed in, will run into the two methods inside (not necessarily two methods will enter)

Where the Dogetauthorizationinfo method is only required for authorization, such as the Administrator role configured in the previous configuration class filterChainDefinitionMap.put("/admin/**", "roles[admin]"); , when entering/admin will enter the Dogetauthorizationinfo method to check the permissions; The Dogetauthenticationinfo method is required for authentication (such as the previous Subject.login() method) to enter

Besides the Usernamepasswordtoken class, we can get the user name and password (which will be used when logging in) from this object new UsernamePasswordToken(username, password); , and the get username or password has the following methods

token.getUsername()  //获得用户名 Stringtoken.getPrincipal() //获得用户名 Object token.getPassword()  //获得密码 char[]token.getCredentials() //获得密码 Object

Note : A lot of people will find, usermapper and other classes, interfaces can not be injected through the @Autowired, run the program will be reported NullPointerException, Online said a lot of such as the Spring loading order, etc. But in fact there is a very important place to pay attention to, Customrealm this class is in the Shiro configuration class securityManager.setRealm() method set in, and many people directly write securityManager.setRealm(new CustomRealm()); , this is not possible, you must use @Bean injected Myrealm, not directly new object:

    @Bean    public SecurityManager securityManager() {        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        // 设置realm.        securityManager.setRealm(customRealm());        return securityManager;    }    @Bean    public CustomRealm customRealm() {        return new CustomRealm();    }

The reason is also very simple, and Controller in the call Service, are Springbean, can not own new

Of course, the same principle can be written:

    @Bean    public SecurityManager securityManager(CustomRealm customRealm) {        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();        // 设置realm.        securityManager.setRealm(customRealm);        return securityManager;    }

Then just add a @Component-like annotation to the Customrealm class

function implementation

The functionality of this article is all implemented in the same way that the interface returns JSON data

Assigning controllers based on URL permissions
游客@RestController@RequestMapping("/guest")public class GuestController{    @Autowired        private final ResultMap resultMap;    @RequestMapping(value = "/enter", method = RequestMethod.GET)    public ResultMap login() {        return resultMap.success().message("欢迎进入,您的身份是游客");    }    @RequestMapping(value = "/getMessage", method = RequestMethod.GET)    public ResultMap submitLogin() {        return resultMap.success().message("您拥有获得该接口的信息的权限!");    }}
普通登陆用户@RestController@RequestMapping("/user")public class UserController{    @Autowired        private final ResultMap resultMap;    @RequestMapping(value = "/getMessage", method = RequestMethod.GET)    public ResultMap getMessage() {        return resultMap.success().message("您拥有用户权限,可以获得该接口的信息!");    }}
管理员@RestController@RequestMapping("/admin")public class AdminController {    @Autowired        private final ResultMap resultMap;    @RequestMapping(value = "/getMessage", method = RequestMethod.GET)    public ResultMap getMessage() {        return resultMap.success().message("您拥有管理员权限,可以获得该接口的信息!");    }}

Suddenly notice the Customrealm class where the accountexception exception was thrown, and now build a class for exception capture

@RestControllerAdvicepublic class ExceptionController {    private final ResultMap resultMap;    @Autowired    public ExceptionController(ResultMap resultMap) {        this.resultMap = resultMap;    }    // 捕捉 CustomRealm 抛出的异常    @ExceptionHandler(AccountException.class)    public ResultMap handleShiroException(Exception ex) {        return resultMap.fail().message(ex.getMessage());    }}

And the logincontroller of landing and other processing.

@RestControllerpublic class Logincontroller {@Autowired private resultmap resultmap;    Private Usermapper Usermapper; @RequestMapping (value = "/notlogin", method = requestmethod.get) public Resultmap Notlogin () {return resultmap. Success (). Message ("You are not logged in!").    "); } @RequestMapping (value = "/notrole", method = requestmethod.get) public Resultmap notrole () {return RESULTM Ap.success (). Message ("You don't have permission!").    "); } @RequestMapping (value = "/logout", method = requestmethod.get) public Resultmap logout () {Subject Subject        = Securityutils.getsubject ();        Deregistration of Subject.logout (); Return resultmap.success (). Message ("Log off successfully!    "); /** * Login * * @param username username * @param password Password */@RequestMapping (value = "/login", met Hod = requestmethod.post) public resultmap Login (string username, string password) {//Create a sub from securityutils        ject Subject Subject = Securityutils.getsubject (); //Prepare token (token) Usernamepasswordtoken token = new Usernamepasswordtoken (username, password) before the certificate is submitted;        Execute Authentication Login Subject.login (token);        According to the permission, specify the return data String role = Usermapper.getrole (username);        if ("User". Equals (role)) {return resultmap.success (). Message ("Welcome login");        } if ("Admin". Equals (role)) {return resultmap.success (). Message ("Welcome to Admin page"); } return Resultmap.fail (). Message ("Permission Error!    "); }}
Test

Teach you Shiro integrate springboot, avoid all kinds of pits

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.