Hi, All.
I am totally new for Shiro. I understood most of people can use XML
configuration both for Spring MVC and Shiro.
but since Spring 3.0 + (if I am wrong, please correct me). Spring suggest the
first choice is java code config for Spring MVC.
so I when switch my app to SpringMVC, I tried to use Shiro with java code
config, Unfortunately, there is a few document talked about this thing, even
on the Shiro official site. so, I sent email out ask help in this list.
thanks for Brian’s help. and thanks google , I tried Many times. finally, I
make it work prefect. so, I think I should be write these down. and share
with people who want to use Shiro in Springmvc with java code config.
the first thing we should understand java code config, we have to use subclass
the class :WebApplicationInitializer for register filter for Shiro. also, we
have to subclass AbstractAnnotationConfigDispatcherServletInitializer for
springmvc and load the mainly configuration files.
you can do these in one class too. but I like use two. one is for springmvc and
another one is just for Shiro.
here’s code:
class: WebApplicationInitializer, it is just for Spring MVC
public class WebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { MvcConfiguration.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
class: WebApplicationForShiroInitializer, this is just for Shiro.
public class WebApplicationForShiroInitializer implements
WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws
ServletException {
FilterRegistration.Dynamic shiroFilter =
servletContext.addFilter("shiroFilter",
DelegatingFilterProxy.class);
shiroFilter.setInitParameter("targetFilterLifecycle", "true");
shiroFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class),
false, "/*");
}
}
since Servlet 3.0, the container can be found class implements interface :
WebApplicationInitializer by automatic. and use it for configuration instead
web.xml
so, let’s say, we are ready for web.xml(actually, we use two class for
web.xml).
right now, we need configuration the Shiro. I put the Shiro configuration into
Rootconfig.class
here’s the Code for RootConfig
@Configuration
@ComponentScan("com.puyangnet.customer.qingfei.beans")
@PropertySource("classpath:druid.properties")
public class RootConfig implements EnvironmentAware {
//define the Database source
@Bean(name="dataSource")
public DruidDataSource getDataSource() {
DruidDataSource myDataSource = new DruidDataSource();
myDataSource.setUrl(load("druid.url"));
myDataSource.setUsername(load("druid.username"));
myDataSource.setPassword(load("druid.password"));
myDataSource.setInitialSize(loadInt("druid.initialSize"));
myDataSource.setMinIdle(loadInt("druid.minIdle"));
myDataSource.setMaxActive(loadInt("druid.maxActive"));
myDataSource.setMaxWait(loadInt("druid.maxWait"));
myDataSource.setTimeBetweenEvictionRunsMillis(
loadLong("druid.timeBetweenEvictionRunsMillis"));
myDataSource.setMinEvictableIdleTimeMillis(
loadLong("druid.minEvictableIdleTimeMillis")
);
myDataSource.setValidationQuery(
load("druid.validationQuery")
);
myDataSource.setTestWhileIdle(
loadBoolean("druid.testWhileIdle")
);
myDataSource.setTestOnBorrow(
loadBoolean("druid.testOnBorrow")
);
myDataSource.setTestOnReturn(
loadBoolean("druid.testOnBorrow")
);
myDataSource.setPoolPreparedStatements(
loadBoolean("druid.poolPreparedStatements")
);
LOGGER.info(myDataSource);
return myDataSource;
}
//define ShiroFilter
@Bean(name="shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new
ShiroFilterFactoryBean();
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSecurityManager(securityManager());
shiroFilterFactoryBean.setSuccessUrl("/home”);
//define some filter for rules
shiroFilterFactoryBean.setFilterChainDefinitionMap(
GetPropertiesToHashMap.getMap("shirofilter.properties")
);
return shiroFilterFactoryBean;
}
//define SecurityManager.
@Bean
public DefaultWebSecurityManager securityManager() {
//use Native Session
SessionManager sessionManager = new DefaultWebSessionManager();
//use Memory Cache Manager
CacheManager cacheManager = new MemoryConstrainedCacheManager();
DefaultWebSecurityManager securityManager = new
DefaultWebSecurityManager();
securityManager.setRealm(myRealm());
securityManager.setSessionManager(sessionManager);
securityManager.setCacheManager(cacheManager);
return securityManager;
}
//define the Realm that by yourself.
//most of you just change the database query sql, you can
//read the code for JdbcRealm
@Bean
public CustomJDBCRealm myRealm() {
CustomJDBCRealm realm = new CustomJDBCRealm();
realm.setCredentialsMatcher(bcryptPasswordMatcher());
realm.setDataSource(getDataSource());
return realm;
}
//if you don’t use Bcrypt, just ignore this one
@Bean
public BcryptPasswordMatcher bcryptPasswordMatcher() {
return new BcryptPasswordMatcher();
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
@DependsOn(value="lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
@Bean
public AuthorizationAttributeSourceAdvisor
authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor advisor = new
AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager());
return advisor;
}
// it is not related with Shiro
public String load(String propertyName)
{
return env.getRequiredProperty(propertyName);
}
// it is not related with Shiro
public int loadInt(String propertyName)
{
return env.getRequiredProperty(propertyName, Integer.class);
}
// it is not related with Shiro
public long loadLong(String propertyName)
{
return env.getRequiredProperty(propertyName, Long.class);
}
// it is not related with Shiro
public boolean loadBoolean(String propertyName)
{
return env.getRequiredProperty(propertyName, Boolean.class);
}
@Override
public void setEnvironment(Environment environment) {
this.env = environment;
}
private Environment env;
private static final Logger LOGGER =
LogManager.getLogger(RootConfig.class.getName());
}
and another thing we use a help class for get all properties to a hash map
public class GetPropertiesToHashMap implements Serializable {
public static final HashMap<String, String> getMap(String fileName) {
ClassPathResource resource = new ClassPathResource(fileName);
Properties properties = new Properties();
if ( resource.exists() ) {
try {
properties.load(resource.getInputStream());
HashMap<String, String> testMap = new
HashMap<String, String>();
Set<Entry<Object, Object>> set =
properties.entrySet();
Iterator<Map.Entry<Object, Object>> it =
set.iterator();
String key = null, value = null;
while (it.hasNext()) {
Entry<Object, Object> entry = it.next();
key = String.valueOf(entry.getKey());
value = String.valueOf(entry.getValue());
key = key == null ? key : key.trim();
value = value == null ? value :
value.trim();
// 将key-value放入map中
LOGGER.info("Key:" + key);
LOGGER.info("Value: " + value);
testMap.put(key, value);
}
return testMap;
} catch ( IOException e) {
LOGGER.error(e.getMessage());
return null;
}
} else {
return null;
}
}
private static final Logger LOGGER =
LogManager.getLogger(GetPropertiesToHashMap.class.getName());
private static final long serialVersionUID = -4052711977651801603L;
}
the filter configuration file content:
#main path configuration. it is global security configuration too
/css/*=anon
/js/**=anon
/images/**=anon
/lib/**=anon
/check-user-by-name/**=anon
/submit-login=anon
/login=anon
/**=authc
#the administrator will be use the whole system
/**=user[admin]
/**=roles[admin]
have fun. everyone
Mike