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