Shiro configuration in Spring projects

(1) Web.xml configuration

<! -- Shiro filter -->
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>/ *</url-pattern>
	</filter-mapping>
        

Copy the code

(2) Shiro and Spring integrated configuration

        <! -- Use Shiro security check annotations -->
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />
	
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>
Copy the code
	<! -- Shiro's lifecycle handler -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
 
	<! -- Shiro's own password matcher (used to verify passwords enough) -->
	 <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.SimpleCredentialsMatcher"></bean>  
	<! -- security datasource: -->
	<bean id="myRealm" class="cc.eguid.service.shiro.MyRealm">
		<property name="credentialsMatcher" ref="credentialsMatcher"/><! -- Password matcher -->
        <property name="cachingEnabled" value="false"/><! -- Disable caching -->
	</bean>
	<! -- Security Manager -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="myRealm" />
	</bean>
	<! -- Shiro filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<! -- Configure security Manager -->
		<property name="securityManager" ref="securityManager" />
		<! -- address of authentication failed jump -->
		<property name="loginUrl" value="/login/" />
		<! -- address of successful authentication jump -->
		<property name="successUrl" value="/" />
		<! -- Address of the jump after permission authentication failure -->
		<property name="unauthorizedUrl" value="/login/unauthorized" />
		<property name="filterChainDefinitions">
			<! --anon indicates anonymous access without authentication or authorization -->
			<! --authc: no access allowed without authentication -->
			<! Roles [admin] -- roles[admin] -->
			<value>
				/static/** = anon
				/login/** = anon
				/common/** = anon
				/admin/** = authc,roles[admin]
				/* = authc
				/** = authc
			</value>
		</property>
	</bean>
Copy the code

Realm and custom password validator implementations

Realm implementation

public class MyRealm extends AuthorizingRealm{
	Logger log=Logger.getLogger(MyRealm.class);
	
	@Autowired
    private UserService userService;// This is the user information operation class, implement user information, user role information, user permission information query function
 
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		UserInfo user = (UserInfo) principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// Query role information
		Collection<String> roles = userService.findRoles(user);
		info.addRoles(roles);
		log.info("Shiro gets the list of roles the user belongs to:"+roles);
		// Query permission information
		Collection<String> permissions = userService.findPermissions(user.getSystemuserid());
		info.addStringPermissions(permissions);
		log.info("Shiro gets user permission list:"+permissions);
		return info;
	}
 
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)throws AuthenticationException{
		// User name and password entered by the user
		String loginname=  token.getPrincipal().toString();
		Object password=token.getCredentials();
		log.info("Shiro is processing information about a user trying to log in:"+loginname+", password:+new String((char[])password));
		// User information in the database
		UserInfo user =userService.queryUserInfoByLoginName(loginname);
		if(user==null||CommonUtil.isNull(user.getLoginusername(),user.getPassword(),user.getSystemuserid())){
			return null;
		}
		log.info("Shiro gets real data on current user login attempts:"+user.getLoginusername()+", password:+user.getPassword());
		// The correct account information in the database
		AuthenticationInfo accountInfo =new SimpleAuthenticationInfo(user, user.getPassword(),getName());
				
		// Obtain the password validator by yourself (shiro implements a password verification method that directly throws an exception if the password is wrong, so it is not used, so it is changed to manual verification directly)
		CredentialsMatcher matcher=getCredentialsMatcher();
		if(matcher==null){
			log.error("No password matcher configured");
			return null;
		}
		// Verify password
		if(matcher.doCredentialsMatch(token,accountInfo)){
			return accountInfo;// If the verification succeeds, the account information is returned
		}
		
		return null; }}Copy the code

2. Customize the password validator

/** * Custom shiro password matching (password is md5 salting based on md5 hash value, salting value is not saved in database, but in configuration file) *@author eguid
 *
 */
public class MyCredentialsMatcher extends CodecSupport implements CredentialsMatcher {
	private static final Logger log = LoggerFactory.getLogger(MyCredentialsMatcher.class);
 
	protected Object getCredentials(AuthenticationToken token) {
		return token.getCredentials();
	}
 
	protected Object getCredentials(AuthenticationInfo info) {
		return info.getCredentials();
	}
 
	@Autowired
	private CommonConfigs commonConfigs;
	/** * Verify password **@param tokenCredentials
	 * @param accountCredentials
	 * @return* /
	protected boolean equals(Object tokenCredentials, Object accountCredentials) {
		if (log.isDebugEnabled()) {
			log.debug("Performing credentials equality check for tokenCredentials of type ["
					+ tokenCredentials.getClass().getName() + " and accountCredentials of type ["
					+ accountCredentials.getClass().getName() + "]");
		}
		if (isByteSource(tokenCredentials) && isByteSource(accountCredentials)) {
			if (log.isDebugEnabled()) {
				log.debug("Both credentials arguments can be easily converted to byte arrays. Performing "
						+ "array equals comparison");
			}
			byte[] tokenBytes = toBytes(tokenCredentials);
			byte[] accountBytes = toBytes(accountCredentials);
			return MessageDigest.isEqual(tokenBytes, accountBytes);
		} else {
			returnaccountCredentials.equals(tokenCredentials); }}public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		Object tokenCredentials = getCredentials(token);
		Object accountCredentials = getCredentials(info);
		String account=String.valueOf((char[])tokenCredentials);
		if(commonConfigs.getMd5salt()==null) {if (log.isDebugEnabled()) {
				log.debug("The salt value in the configuration file is empty, the password cannot be matched, please confirm whether the configuration file is in the specified location or configure the specified salt value.");
			}
			return false;
		}
		String saltaccount=MD5Util.getMD5(account, commonConfigs.getMd5salt());
		if (log.isDebugEnabled()) {
			log.debug("Salt password:"+saltaccount);
		}
		returnequals(accountCredentials, saltaccount.toCharArray()); }}Copy the code

Iii. Use of annotations and template tags (annotations are invalid)

1. Use of annotations

@RequiresPermissions({"user:update:view"})// Check the operation permissions

@RequiresPermissions(value={"user:add","user:view"},logical=Logical.OR)// One of the two operation permissions can pass the check

@RequiresRoles({"admin"})// Check the role

@RequiresRoles(value={"debug","admin"},logical=Logical.OR)// One of the two roles meets the criteria


@RequiresAuthentication// Check whether shiro is certified
@RequiresGuest// No validation is required
@RequiresUser// Check whether the user is a user in the current system
Copy the code

2. Label use

<%@taglib prefix=”shiro” uri=”shiro.apache.org/tags” %>

(1) Display user identity information

<shiro: principal/>
Copy the code

The default is to call subject.getPrincipal ()

<shiro:principal property="username"/>
Copy the code

Equivalent to ((User) Subject. GetPrincipals ()). The getUsername ()

(2) Shiro login user is displayed

 <shiro:user>Welcome [<shiro:principal/>] login,<a href="logout">exit</a>  
<shiro:user>
Copy the code

(3) Anonymous user access

<shiro:guest>Unshiro authenticated users (tourists, anonymous users)</shiro:guest>  
Copy the code

(4) Those who have logged in to Shiro (logged in users)

 <shiro:authenticated>The user [<shiro:principal/>] The authentication is successful<shiro:authenticated> 
Copy the code

(5) Those who have not logged in shiro

 <shiro:notAuthenticated>Unauthenticated (including remember me)<shiro:notAuthenticated>
Copy the code

(6) Check roles

 <shiro:hasRole name="admin">The user [<shiro:principal/>] Has the role admin<br/>
 <shiro:hasRole>
Copy the code

Check any character (pass if one of them meets the criteria, equivalent to OR)

 <shiro:hasAnyRoles name="admin,user">The user [<shiro:principal/>] Has the role admin or user<br/>
 <shiro:hasAnyRoles>
Copy the code

No role (reverse judgment)

 <shiro:lacksRole name="abc">The user [<shiro:principal/>] does not have role ABC<br/>
 <shiro:lacksRole>
Copy the code

(7) Judgment of operation permission

 <shiro:hasPermission name="user:create">The user [<shiro:principal/>] Have permission user:create<br/>  
 <shiro:hasPermission>    
Copy the code

No operation permission (reverse judgment)

 <shiro:lacksPermission name="org:create">The user [<shiro:principal/>] no permissions org:create<br/>  
 <shiro:lacksPermission>  
Copy the code

Fourth, the annotation is not effective solution

Put Shiro annotations after springMVC’s annotation scan (i.e. loaded in the springMVC container)

<! -- Use Shiro security check annotations -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" />
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager" />
</bean>
Copy the code

Shiro annotations take effect by scanning the above directly into the servlet-context.xml below

<! -- springMVC application -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>2</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
Copy the code