shiro与spring,springmvc的简单整合(JavaConfig)
(初来乍到,请多包含)
导入核心包,maven会自动导入依赖的包
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
配置类
配置springmvc的前端控制器
@Configuration
public class MyWebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 增加过滤器
* @return
*/
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter("utf-8");
// DelegatingFilterProxy作用是自动到Spring 容器查找名字为shiroFilter(filter-name)的bean并把所有Filter 的操作委托给它。
// 1. 配置 Shiro 的 shiroFilter.
// 2. DelegatingFilterProxy 实际上是 Filter 的一个代理对象. 默认情况下, Spring 会到 IOC 容器中查找和
// <filter-name> 对应的 filter bean. 也可以通过 targetBeanName 的初始化参数来配置 filter bean 的 id.
DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
delegatingFilterProxy.setTargetFilterLifecycle(true);
delegatingFilterProxy.setTargetBeanName("shiroFilterFactoryBean");
return new Filter[]{encodingFilter,delegatingFilterProxy};
}
/**
* spring的配置类
* @return
*/
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
/**
* springmvc的配置类
* @return
*/
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{ServletConfig.class};
}
/**
* 拦截的路径
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
必须配置DelegatingFilterProxy ,否则shiro的filter就会不起作用
spring配置类
@Component
@ComponentScan(basePackages = {"com.cca"},
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class))
//@Import(ShiroConfig.class)
@EnableAspectJAutoProxy
public class RootConfig {
/**
* 配置解析${}表达式 作用等于xml中property-placeholder标签
* @return
*/
@Bean
public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
return new PropertySourcesPlaceholderConfigurer();
}
}
PropertySourcesPlaceholderConfigurer 是用来解析spel表达式的。
springmvc的配置类
/**
* Author cca
* Created by 1398024451@qq.com on 2020/9/28 19:09
*/
@Component
@ComponentScan(basePackages = {"com.cca.controller"})
public class ServletConfig {
}
webmvc的配置
/**
* Author cca
* Created by 1398024451@qq.com on 2020/9/28 19:20
*/
@Configuration
public class MyWebMvcConfig extends WebMvcConfigurationSupport {
@Autowired
private ServletContext servletContext;
/**
* 模板解析器
* @return
*/
@Bean
public ITemplateResolver iTemplateResolver(){
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);
templateResolver.setPrefix("/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("utf-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
templateResolver.setCacheable(false);//缓存
return templateResolver;
}
/**
* 生成模板引擎
* @param iTemplateResolver
* @return
*/
@Bean
public ISpringTemplateEngine iSpringTemplateEngine(ITemplateResolver iTemplateResolver){
SpringTemplateEngine springTemplateEngine = new SpringTemplateEngine();
springTemplateEngine.setTemplateResolver(iTemplateResolver);
return springTemplateEngine;
}
/**
* thymeleaf解析器
* @param iSpringTemplateEngine
* @return
*/
@Bean
public ThymeleafViewResolver resolver(ISpringTemplateEngine iSpringTemplateEngine){
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(iSpringTemplateEngine);
viewResolver.setCharacterEncoding("utf-8");
return viewResolver;
}
//过滤静态资源
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
registry.addResourceHandler("/index.html").addResourceLocations("/index.html");
}
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
spring的jdbctemplate配置
因为不需要复杂的查询语句,所以博主用了spring的jdbcTemplate来做简单的查询。
@Configuration
@PropertySource(value = "classpath:jdbc.properties")
public class JdbcTemplateConfig {
@Value("${url}")
private String url;
@Value("${diverClass}")
private String driver;
@Value("${user}")
private String user;
@Value("${pwd}")
private String pwd;
@Bean
public DataSource dataSource(){
System.out.println(url+"\n"+ user+"\n"+pwd);
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(pwd);
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
}
shiro配置
/**
* Author cca
* Created by 1398024451@qq.com on 2020/9/28 20:13
*/
@Configuration
public class ShiroConfig {
/**
* 开启shiro权限注解支持
* @param webSecurityManager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager webSecurityManager){
AuthorizationAttributeSourceAdvisor sourceAdvisor = new AuthorizationAttributeSourceAdvisor();
sourceAdvisor.setSecurityManager(webSecurityManager);
return sourceAdvisor;
}
/**
* 工厂
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(securityManager);
Map<String ,String> map = new HashMap<>();
map.put("/index.html", "anon");//放行
map.put("/user/*","anon");
map.put("/**", "authc");//拦截
filterFactoryBean.setLoginUrl("/login");//登录界面
filterFactoryBean.setUnauthorizedUrl("/user/error");
filterFactoryBean.setFilterChainDefinitionMap(map);
return filterFactoryBean;
}
@Bean
public Realm realm(){
CustomerRealm customerRealm = new CustomerRealm();
//密码匹配器
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");//加密方式
matcher.setStoredCredentialsHexEncoded(true);
matcher.setHashIterations(1024);//散列次数
customerRealm.setCredentialsMatcher(matcher);
return customerRealm;
}
/**
* 创建安全管理器
* @param realm
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(Realm realm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
}
自定义realm配置
/**
* Author cca
* Created by 1398024451@qq.com on 2020/9/28 20:16
*/
public class CustomerRealm extends AuthorizingRealm {
@Autowired //CustomerRealm 通过@bean加入了spring容器,所有能够自动注入
private UserService userService;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String principal = (String) principalCollection.getPrimaryPrincipal();
//System.out.println(principal);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.addRole("admin1");//增加角色
return authorizationInfo;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String principal = (String) authenticationToken.getPrincipal();
String credentials = new String((char[])authenticationToken.getCredentials());
System.out.println(principal+" "+ credentials);
//查询用户
User user = userService.getUserByName(principal);
if(user != null){
SimpleAuthenticationInfo authenticationInfo =
new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(),ByteSource.Util.bytes(user.getSalt()),this.getName());
return authenticationInfo;
}
return null;
}
}
实体类User
@Setter
@Getter
@ToString
public class User {
private int id;
private String username;
private String password;
private String salt;
}
这里博主用了lombok插件,如果没有安装插件就生成getset方法
Dao层
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public User getUserByName(String username){
String sql = "select * from user where username = ?";
RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class);
User user = jdbcTemplate.queryForObject(sql, rowMapper,username);
return user;
}
}
service层
只是简单的查询语句,所以博主没有定义业务接口。
@Service
public class UserService {
@Autowired
private UserDao userDao;
public User getUserByName(String username){
return userDao.getUserByName(username);
}
}
controller层
@Controller
@RequestMapping("user")
public class MyController {
@Autowired
private UserService userService;
// @ResponseBody
@RequestMapping("logincheck")
@Log(log = "登录")
public String test(String username, String pwd, Model model){
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,pwd);
try {
subject.login(token);
}catch (Exception e){
System.out.println("用户名或密码错误");
model.addAttribute("msg", "用户名或密码错误");
return "login";
}
return "success";
}
@ResponseBody
@RequestMapping("del")
@Log(log = "删除")
@RequiresRoles(value = "admin")
public String del(String username){
System.out.println("del.............");
return "success";
}
@RequestMapping("logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}
}
使用shiro的权限注解必须要在容器中加入AuthorizationAttributeSourceAdvisor



点击删除时会调用contro中的del方法, 改方法上标注了@RequiresRoles(value = "admin") 并设置访问角色位
admin。但是博主在登录授权时给用户授予admin1的权限,可是最后还是跳到了成功页面。这就是容器中没有加
入AuthorizationAttributeSourceAdvisor类。
AuthorizationAttributeSourceAdvisor就相当于一个切入点。


AuthorizationAttributeSourceAdvisor加入容器后,注解起作用了。但是却直接爆了异常,可是博主明明在shiro配置类里配置了没有权限的跳转地址,这个却没有有作用。这里就不细说原因了,直接给出解决方案
/**
* Author cca
* Created by 1398024451@qq.com on 2020/10/13 14:42
*/
@ControllerAdvice
public class MyException {
/**
* shiro无权限异常处理
* @return
*/
//@ExceptionHandler(value = UnauthorizedException.class)
public String unauthorizedException(){
return "error";
}
}
直接定义一个全局异常处理类,处理这个异常。
(初来乍到,请多包含)
本文介绍了如何将Shiro与Spring、SpringMVC进行简单的整合,通过JavaConfig方式进行配置。内容包括:配置前端控制器、Spring配置、SpringMVC配置、数据库连接配置、Shiro配置、自定义Realm、User实体类、Dao、Service及Controller层的设置。

1241

被折叠的 条评论
为什么被折叠?



