shiro framework and spring integration in my java history

Posted by Kuraden on Wed, 11 Mar 2020 10:05:20 +0100

Any framework needs to use pom dependency first...

Configure Shiro related information in shiro.xml configuration file

Because securityManager needs realm

package com.ssq.realm;


import com.ssq.pojo.User;
import com.ssq.service.RoleService;
import com.ssq.service.UserService;
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.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

public class UserRealm extends AuthorizingRealm {
    @Autowired
    private UserService us;
    @Autowired
    private RoleService rs;


    /**
     * To grant authorization
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
       User user= (User) principals.getPrimaryPrincipal();
        //Get the role and authority of the account according to the user name
       Set<String> roles= rs.findRoles(user.getLoginName());
       Set<String> permissions= rs.findPermissions(user.getLoginName());
       SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo();
       //Give the found permission to SimpleAuthorizationInfo for judgment
       sai.addRoles(roles);
       sai.addStringPermissions(permissions);
       return sai;
    }


    /**
     * Authentication
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username =(String) token.getPrincipal();
        User user= us.findByLoginName(username);
        //Judge that the user does not exist
        if (user==null) {
            throw new UnknownAccountException();
        }
        return new SimpleAuthenticationInfo(
                user,//User information user object
                user.getPassword(),//Password
                ByteSource.Util.bytes(user.getLoginName()),//salt
                getName()//Name of the realm
        );
    }
}

I wrote about realm in java class
The realm in this class uses the service to find dao dao and mapper to find out the user's role and permission according to the user name

  @RequestMapping("/login")
    public String login(String loginName, String password, Model model, HttpSession session){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(loginName,password);
        try {
            subject.login(token);
            User user = (User) subject.getPrincipal();
            //session provided by http
            //session.setAttribute("user",user);
            //Use session provided by shiro
            System.out.println(subject.getSession()==session);
            subject.getSession().setAttribute("user",user);
            //The session of http is the same as shiro
            return "forward:/product/findAll";
        }catch (UnknownAccountException e){
          model.addAttribute("loginError","user name does not exist");
        }catch (IncorrectCredentialsException e){
          model.addAttribute("loginError","Incorrect password");
        }catch (AuthenticationException e){
            model.addAttribute("loginError","Landing failed");
        }
        return "login";
    }

This is in the controller

In addition, shiro filter rules can only be configured to intercept and authorize all requests after passing shiro filter

package com.ssq.filter;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * Custom role validation filter
 */
public class CustomRolesAuthorizationFilter extends AuthorizationFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o)
            throws Exception {
        Subject subject=getSubject(request,response);
        String[] rolesArray=(String[]) o;

        if (rolesArray==null||rolesArray.length==0){
            return  true;
        }
        //Judge role as long as any role is accessible
        for (int i=0;i<rolesArray.length;i++){
            if (subject.hasRole(rolesArray[i])) {
            return true;
            }
        }
        return false;
    }
}

Then configure it in shiro configuration file

<bean id="customRoles" class="com.ssq.filter.CustomRolesAuthorizationFilter"/>

And web.xml filter

  <! -- configure Shiro fi lt er to intercept all requests for authentication and authorization -- >
    As like as two peas in the spring-shiro configuration file, the bean shrioFi lt er--> is exactly the same name.
    <filter>
        <filter-name>shrioFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shrioFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

1. First, password encryption

package com.ssq.service.impl;

import com.ssq.vo.PasswordVo;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class PasswordServiceImpl implements PasswordService {
    @Value("${algorithmName}")
    private String algorithmName;
    @Value("${hashIterations}")
    private int hashIterations;

    @Override
    public String encryptPassword(Object PasswordVo) throws IllegalArgumentException {
        PasswordVo Vo = (com.ssq.vo.PasswordVo) PasswordVo;
        return new SimpleHash(algorithmName,Vo.getPassword(),Vo.getSalt(),hashIterations).toBase64();
    }

    @Override
    public boolean passwordsMatch(Object submittedPlaintext, String encrypted) {
        return false;
    }
}

Called at the service layer

package com.ssq.service.impl;

import com.ssq.dao.UserDao;
import com.ssq.pojo.User;
import com.ssq.service.UserService;
import com.ssq.vo.PasswordVo;
import org.apache.shiro.authc.credential.PasswordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

@Service
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao ud;
    @Autowired
    private PasswordService ps;

    @Override
    public int register(Map<String, Object> map) {
        //Encrypt the plaintext password
        PasswordVo vo=new PasswordVo();
        String password = (String) map.get("password");
        System.out.println("Password:"+password);
        String loginName =(String) map.get("loginName");
        System.out.println("User name:"+loginName);
        vo.setPassword(password);
        vo.setSalt(loginName);
        //Encrypted password
        String str = ps.encryptPassword(vo);
        Map<String,Object> map1=new HashMap<>();
        map1.put("loginName",loginName);
        map1.put("password",str);
        return ud.register(map1);
    }

This is vo.

package com.ssq.vo;

import java.io.Serializable;

public class PasswordVo implements Serializable {
    private String password;
    private String salt;

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }
}

And configure the algorithm and hash times in the configuration file properties

Then the controller calls the service

@Controller
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService us;

    //register
    @RequestMapping("/register")
    public String register(String loginName,String password){
        Map<String,Object> map=new HashMap<>();
        map.put("loginName",loginName);
        map.put("password",password);
        us.register(map);
        return "login";
    }

Then password decryption login

 //Sign in
    @RequestMapping("/login")
    public String login(String loginName, String password, Model model, HttpSession session){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(loginName,password);
        try {
            subject.login(token);
            User user = (User) subject.getPrincipal();
            //session provided by http
            //session.setAttribute("user",user);
            //Use session provided by shiro
            System.out.println(subject.getSession()==session);
            subject.getSession().setAttribute("user",user);
            //The session of http is the same as shiro
            return "forward:/product/findAll";
        }catch (UnknownAccountException e){
          model.addAttribute("loginError","user name does not exist");
        }catch (IncorrectCredentialsException e){
          model.addAttribute("loginError","Incorrect password");
        }catch (AuthenticationException e){
            model.addAttribute("loginError","Landing failed");
        }
        return "login";
    }

Login means decryption

    /**
     * Authentication
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String username =(String) token.getPrincipal();
        User user= us.findByLoginName(username);
        //Judge that the user does not exist
        if (user==null) {
            throw new UnknownAccountException();
        }
        return new SimpleAuthenticationInfo(
                user,//User information user object
                user.getPassword(),//Password
                ByteSource.Util.bytes(user.getLoginName()),//salt
                getName()//Name of the realm
        );
    }
}

realm requires a password matcher

    <! -- configure password matcher -- >
    <! -- realm requires a password matcher -- >
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <! -- password matcher requires algorithm -- >
        <! -- this is the algorithm configured in encrypt.properties and the number of hashes. After that, you only need to change the algorithm -- >
        <property name="hashAlgorithmName" value="${algorithmName}"></property>
        <! -- number of hashes -- >
        <property name="hashIterations" value="${hashIterations}"></property>
        <! -- the encoding method used in UserServiceImpl is tobase64 and the defau lt encoding method is hexadecimal -- >
        <! -- so we need to change the defau lt to false -- >
        <property name="storedCredentialsHexEncoded" value="false"></property>
    </bean>

Login succeeded. Query the user's permissions and roles according to the user name

<mapper namespace="com.ssq.dao.RoleDao">
    <select id="selectRoles" resultType="string" parameterType="string">
        select tr.role_name
        from shiro.t_user tu
         left join shiro.user_role ur
            on tu.id=ur.user_id
         left join shiro.t_role tr
            on ur.role_id=tr.id
        where tu.login_name=#{username}
    </select>

    <select id="selectPermissions" resultType="string" parameterType="string">
        select tp.permission_name
        from shiro.t_user tu
            left join shiro.user_role ur
            on tu.id=ur.user_id
            left join shiro.t_role tr
            on ur.role_id=tr.id
            left join shiro.role_permisstion rp
            on rp.role_id=tr.id
            left join shiro.t_permisstion tp
            on tp.id=rp.permission_id
        where tu.login_name=#{username}
    </select>

  <! -- define a bean named shrioFilter whose id should be consistent with the shiro filter name configured by web.xml -- >
    <! -- used to configure url fi lt ering rules -- >
    <bean id="shrioFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <! -- configure securitymanager -- >
        <property name="securityManager" ref="securityManager"></property>

        <! -- configure url fi lt ering rules -- >
        <property name="filterChainDefinitions">
            <value>
                <! -- anon does not need login authentication -- >
                <! -- authc requires login authentication -- >
                /showLogin= anon
                 /product/**=authc
                /teacher/delete=authc,perms[teacher:delete]
                <! -- the validation of the permission to be overridden here defau lt s to the relationship between and. Here, after rewriting, the login only needs to satisfy one of the roles -- >
                /teacher/**=authc,customRoles[teacher,manager]
                /student/**=authc,roles[student]
            </value>
        </property>
Published 2 original articles, won praise 1 and visited 7
Private letter follow

Topics: Shiro Apache Session Java