SpringBoot整合Shiro
SpringBoot整合Shiro
SpringBoot整合Shiro流程
- 引入shiro-spring依赖
- 编写自定义的Realm它需要继承于AuthorizingRealm。
- 编写ShiroConfig
- 使用Shiro
引入shiro-spring依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
编写自定义Realm
public class UserRealm extends AuthorizingRealm {
/**
*为用户添加角色与权限
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
String username = (String) ((User) principalCollection.getPrimaryPrincipal()).getName();
//添加用户角色
Set<String> roleSets = new HashSet<String>();
roleSets.add("user1");
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(roleSets);
//添加用户权限
Set<String> permissions = new HashSet<String>();
permissions.add("select");
permissions.add("list");
permissions.add("add");
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
/**
* 对用户进行登入验证,用户登入时会将站号密码通过Subject的login方法传入过来
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = UserService.map.get(token.getUsername());
if (user == null) {
return null;
}
if (!user.getPassword().equals("用户密码")) {
return null;
}
return new SimpleAuthenticationInfo(user, user.getPassword(), "");
}
}
编写ShiroConfig
@Configuration
public class ShiroConfig {
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
}
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//配置那些资源路径需要访问权限那些不需要
Map<String, String> filterMap = new HashMap<String, String>();
filterMap.put("/user", "authc");
//这里需要对login页面进行放行让用户可以直接访问这个页面
filterMap.put("/login", "anon");
filterFactoryBean.setFilterChainDefinitionMap(filterMap);
return filterFactoryBean;
}
@Bean(name = "userRealm")
public UserRealm getUserRealm(){
return new UserRealm();
}
/**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解
* 的类,并在必要时进行安全逻辑验证
*/
@Bean
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultSecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
@Bean
@ConditionalOnMissingBean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
defaultAAP.setProxyTargetClass(true);
return defaultAAP;
}
}
使用Shiro
编写登入页面,并对用户进行登入验证:
@RestController
public class UserLogin {
@GetMapping("/login")
public String login(@RequestParam("username") String name, @RequestParam("password") String password) {
UsernamePasswordToken token = new UsernamePasswordToken(name, password);
Subject subject = SecurityUtils.getSubject();
try{
//将账号密码传到UserRealm中对其进行验证
subject.login(token);
}catch (Exception e){
e.printStackTrace();
return "login fail";
}
return "login success";
}
}
使用注解对用户进行权限验证,这需要用户先登入:
@RestController
public class UserController {
@RequiresPermissions("list:add")
@GetMapping("/test")
public String test(){
return "you have permission!";
}
}
更进一步
当用户访问一个页面时,如果用户没有权限那么用户将会跳转到Shiro定义的toLogin页面,如果是一个前后端分离的项目这样显然是不可取的,通过下面的方法可以让用户得到认证失败的信息而不是跳转页面。
- 编写自定义Filter:这个Filter需要继承于FormAuthenticationFilter并覆写onAccessDenied方法。
- 将这个Filter添加到ShiroConfig配置类的getShiroFilterFactoryBean方法里
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(200);
httpServletResponse.setContentType("application/json;charset=utf-8");
PrintWriter out = httpServletResponse.getWriter();
out.println("认证失败请重新登入!");
out.flush();
out.close();
return false;
}
}
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//配置那些资源路径需要访问权限那些不需要
Map<String, String> filterMap = new HashMap<String, String>();
filterMap.put("/user", "authc");
filterMap.put("/login", "anon");
filterFactoryBean.setFilterChainDefinitionMap(filterMap);
Map<String, Filter> map = new HashMap<String, Filter>();
map.put("authc", new MyFormAuthenticationFilter());
filterFactoryBean.setFilters(map);
return filterFactoryBean;
}
这样只要是需要权限authc的用户认证失败将不会跳转页面,而是返回失败信息。

浙公网安备 33010602011771号