技术开发 频道

Shiro简介及与spring集成

    代码实现

  自定义Realm

  @Component("myRealm")

  public class UserRealm extends AuthorizingRealm {

  @Autowired

  private UserService userService;

  /**

  * 授权方法,在配有缓存的情况下,只加载一次。

  */

  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

  ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();

  List<Authority> authorities = shiroUser.getAuthorities();

  Set<String> roles = new HashSet<String>();

  for (Authority authority : authorities){

  roles.add(authority.getName());

  }

  SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

  info.setRoles(roles);

  return info;

  }

  /**

  * 登录认证

  * @param token

  * @return

  * @throws AuthenticationException

  */

  @Transactional

  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

  UsernamePasswordToken uptoken = (UsernamePasswordToken) token;

  String username = uptoken.getUsername();

  User user = userService.findUserByLoginName(username);

  if( user == null ) {

  throw new UnknownAccountException("用户名"+username+"不存在.");

  }

  if (user.getEnabled() != 1){

  throw new LockedAccountException(user.getName()+"被锁定");

  }

  ShiroUser principal = new ShiroUser();

  String userInfo = user.getName()+"("+user.getRole().getName()+")";

  principal.setUserInfo(userInfo);

  principal.setAuthorities(user.getRole().getAuthorities());

  Object hashedCredentials = user.getPassword();

  ByteSource credentialsSalt = ByteSource.Util.bytes(user.getSalt());

  String realmName = getName();

  SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,hashedCredentials, credentialsSalt,realmName);

  return info;

  }

  public class ShiroUser{

  //userName(roleName)

  private String userInfo;

  private List<Authority> authorities;

  public List<Authority> getAuthorities() {

  return authorities;

  }

  public void setAuthorities(List<Authority> authorities) {

  this.authorities = authorities;

  }

  public String getUserInfo() {

  return userInfo;

  }

  public void setUserInfo(String userInfo) {

  this.userInfo = userInfo;

  }

  }

  /**

  * 初始化 使用MD5加密

  */

  @PostConstruct

  public void initCredentialsMatcher(){

  HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

  hashedCredentialsMatcher.setHashAlgorithmName("MD5");

  // 加密1024次

  hashedCredentialsMatcher.setHashIterations(1024);

  //

  this.setCredentialsMatcher(hashedCredentialsMatcher);

  }

  }

  Main方法生成salt 和password

  // 利用shiro提供的随机数生成类、生成随机数,用于盐值加密

  SecureRandomNumberGenerator secureRandomNumberGenerator =

  new SecureRandomNumberGenerator();

  String str = secureRandomNumberGenerator.nextBytes().toBase64();

  System.out.println(str);//

  String algorithmName = "MD5";

  Object source = "123456";

  //盐值 NWJtcFg3VFNtNEdEWTh6UUtoSTRkdz09

  ByteSource salt = ByteSource.Util.bytes(str);

  int hashIterations = 1024;

  Object result = new SimpleHash(algorithmName,source,salt,hashIterations);

  System.out.println(result);//数据库中密码 b9aa43cfb15649c932ac647df54101a7

  LoginController.java

  @RequestMapping(value = "/login",method = RequestMethod.POST)

  private String login(HttpServletRequest request,Modelmodel,

  @RequestParam(name = "username",required = false) String username, @RequestParam(name = "password",required = false) String password, RedirectAttributes attributes){

  UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);

  //usernamePasswordToken.setRememberMe(false);

  Subject subject = SecurityUtils.getSubject();

  String message = null;

  if(!subject.isAuthenticated()){

  try {

  subject.login(usernamePasswordToken);

  } catch (UnknownAccountException ex) {//用户名没有找到

  //ex.printStackTrace();

  message = "用户名不存在";

  } catch (IncorrectCredentialsException ex) {//用户名密码不匹配

  // ex.printStackTrace();

  message = "用户名和密码不匹配";

  }catch (LockedAccountException lae) {// 用户被锁定

  //lae.printStackTrace();

  message = "用户被锁定";

  }catch (AuthenticationException e) {//其他的登录错误

  e.printStackTrace();

  }

  if(message!=null){

  attributes.addFlashAttribute("message", message);

  return "redirect:/shiro-login";

  }

  }

  return "redirect:/success";

  }

  基于注解的权限设置

  在controller list方法上加上 @RequiresRoles(value={"admin"}) 说明此方法需要有admin角色的用户才可以操作。

  @RequiresRoles(value={"admin"})

  @RequestMapping(value = "/list", method= RequestMethod.GET)

  public String list(Model model, HttpServletRequest request){

  List<User> userList=userService.listAll(0,10);

  model.addAttribute("list", userList);

  return "user/userList";

  }

  我们用两个用户来测试

Shiro简介及与spring集成

Shiro简介及与spring集成

  可以看到admin用户可以访问list页面,而gx因为没有admin的角色,访问失败。

  附:数据库关系图

Shiro简介及与spring集成

  总结:本文通过例子,简单实现了权限的控制,相比与spring secruity的复杂配置,shiro更加简单。

  例子github:https://github.com/zhaoguoxin/gxshiro.git

0